Optimizing Mobile App Animations to Achieve 60 FPS

NOVASOLUTIONS.TECHNOLOGY is engaged in the development, support and maintenance of iOS, Android, PWA mobile applications. We have extensive experience and expertise in publishing mobile applications in popular markets like Google Play, App Store, Amazon, AppGallery and others.
Development and support of all types of mobile applications:
Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1 servicesAll 1735 services
Optimizing Mobile App Animations to Achieve 60 FPS
Complex
~2-3 business days
FAQ
Our competencies:
Development stages
Latest works
  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1052
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    445

Optimizing Mobile Animations for 60 FPS

60 FPS means 16.67 ms per frame. If even one frame takes 17+ ms, Instruments shows dropped frame. On 120 Hz displays (ProMotion), threshold is even stricter: 8.3 ms. Users with iPhone 13 Pro and Pixel 8 feel this physically.

Where Frames Are Lost: Diagnostics First

Before optimizing anything — open Xcode Instruments with Core Animation template. Run on real device (simulator doesn't count: different GPU). Look at two graphs: FPS and CPU Usage. Red columns on FPS-graph — dropped frames.

On Android — Android Profiler in GPU/CPU mode + Systrace for detailed trace. In Developer Options enable Profile GPU Rendering (displays bars on screen): if orange zone (Draw) and red (Sync/Upload) regularly exceed 16ms-line — there's problem.

Typical finding: shadow animation (shadowRadius, shadowOffset on CALayer) recalculates Gaussian blur on CPU every frame. On iPhone SE 2nd gen this can give 8–10 ms just for shadow.

Main Principle: GPU Layers vs CPU Rendering

Animate only transform and opacity — not recommendation, this is law of performance. These properties handled by Compositor thread directly, without main thread involvement and without drawRect: call.

Everything else triggers Layout → Display → Prepare → Commit cycle:

Property Where Drawn Dropped Frames
transform, opacity GPU Compositor No
backgroundColor GPU (CALayer) Rarely
bounds, frame CPU → GPU Often
cornerRadius + masksToBounds CPU (offscreen) Often
shadowPath (static) GPU No
shadowRadius (dynamic) CPU Very often

cornerRadius with masksToBounds = true — offscreen rendering. For each such layer, Core Animation does additional render pass. In Instruments: Debug → Color Offscreen-Rendered paints them yellow. Fix: set layer.shadowPath statically or use mask from vector image.

UIKit: Concrete Techniques

shouldRasterize — Use with Caution

layer.shouldRasterize = true caches layer as bitmap. Helps if content doesn't change. Kills if it does: cache invalidated every frame and redrawn more expensive than without it. Check through Instruments → Color Hits Green and Misses Red: red = invalidation, no help.

drawRect vs CALayer

Overriding drawRect: — nuclear option. If call happens during animation (e.g., bounds changes), main thread busy drawing. Alternative: move static content to separate CALayer with contents = image.cgImage, animate only transform.

CADisplayLink for Custom Animations

If writing custom animation on CADisplayLink — bind to preferredFramesPerSecond:

let displayLink = CADisplayLink(target: self, selector: #selector(tick))
displayLink.preferredFrameRateRange = CAFrameRateRange(
    minimum: 60,
    maximum: 120,
    preferred: 120
)
displayLink.add(to: .main, forMode: .common)

On ProMotion devices this allows animations to run at 120 FPS. Without range specification, system may fix 60 even on 120 Hz display.

Lottie: Common Performance Issues

Lottie by default uses .automatic render mode. On complex animations with masks and trim paths, this often means CPU rendering. Force switch:

animationView.renderingEngine = .coreAnimation

Core Animation engine (.coreAnimation) renders through CALayers — without main thread participation. Limitation: doesn't support some complex effects (gradients through trim paths, some blending modes). Check in Lottie Diagnostics.

Compose: Recommendations

Modifier.graphicsLayer instead of direct layout parameter changes:

// Bad: calls relayout every frame
Box(modifier = Modifier.size(animatedSize))

// Good: only GPU transform, layout stable
Box(modifier = Modifier
    .size(100.dp)
    .graphicsLayer { scaleX = animatedScale; scaleY = animatedScale }
)

graphicsLayer works like layer.transform in UIKit — outside layout pass.

Avoid remember { mutableStateOf() } inside animation lambda. Each state update through mutableStateOf triggers recomposition. Use Animatable directly, or animateFloatAsState which updates only graphicsLayer without screen recompose.

Typical Optimization Cases

Client app's list with custom cells dropped to 40 FPS during scroll. Reason: each cell had layer.cornerRadius = 12 with masksToBounds = true and layer.shadowRadius = 8. Double offscreen render pass per cell. Solution: corner radius through UIBezierPath mask (one GPU pass), shadow through shadowPath with pre-calculated CGPath. FPS returned to 60 stably.

Optimization Process

Profile in Instruments / Android Profiler on real devices (minimum one slow device from target audience). Identify offscreen rendering, expensive draw calls, CPU-animations. Sequentially eliminate with measurement after each change. Regression testing on devices of different classes.

Timeframe Guidelines

Audit and fixing animations in existing application — 2–5 days depending on scale and number of problem areas.