FPS Optimization and Animation Performance
Introduction to FPS Optimization
Understanding Frame Rate Performance
Frame rate optimization is crucial for delivering smooth user experiences in mobile applications. The human eye perceives motion as smooth when the frame rate is at least 24 FPS, but modern mobile devices target 60 FPS (16.67ms per frame) or even 120 FPS (8.33ms per frame) for premium devices.
Performance Metrics
- Target Frame Rates: 60 FPS (16.67ms budget), 120 FPS (8.33ms budget)
- Jank Detection: Frame drops below 60 FPS threshold
- Performance Budget: Maximum time allowed for each frame rendering
Platform-Specific FPS Optimization
Android FPS Optimization
GPU Overdraw Reduction
kotlin
// Minimize overdraw with efficient layouts
class OptimizedViewGroup @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : ViewGroup(context, attrs) {
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
// Efficient layout implementation
children.forEach { child ->
child.layout(
child.left,
child.top,
child.right,
child.bottom
)
}
}
override fun dispatchDraw(canvas: Canvas) {
// Minimize overdraw in drawing operations
canvas.clipRect(0, 0, width, height)
super.dispatchDraw(canvas)
}
}
Hardware Acceleration
kotlin
// Enable hardware acceleration for smooth animations
class AnimatedView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : View(context, attrs) {
init {
setLayerType(LAYER_TYPE_HARDWARE, null)
}
fun startAnimation() {
animate()
.translationX(200f)
.setDuration(300)
.setInterpolator(FastOutSlowInInterpolator())
.start()
}
}
Choreographer Frame Monitoring
kotlin
class FrameRateMonitor {
private val choreographer = Choreographer.getInstance()
private var lastFrameTime = 0L
private var frameCount = 0
private val frameCallback = object : Choreographer.FrameCallback {
override fun doFrame(frameTimeNanos: Long) {
if (lastFrameTime > 0) {
val frameDuration = (frameTimeNanos - lastFrameTime) / 1_000_000
if (frameDuration > 16.67) {
// Frame drop detected
Log.w("FPS", "Frame drop: ${frameDuration}ms")
}
}
lastFrameTime = frameTimeNanos
frameCount++
choreographer.postFrameCallback(this)
}
}
fun startMonitoring() {
choreographer.postFrameCallback(frameCallback)
}
}
iOS FPS Optimization
Core Animation Optimization
swift
class OptimizedAnimationView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
// Enable rasterization for complex views
layer.shouldRasterize = true
layer.rasterizationScale = UIScreen.main.scale
}
func performOptimizedAnimation() {
// Use Core Animation for better performance
let animation = CABasicAnimation(keyPath: "transform.translation.x")
animation.toValue = 200
animation.duration = 0.3
animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
layer.add(animation, forKey: "translation")
}
}
Metal Performance Shaders
swift
import MetalPerformanceShaders
class MetalRenderer {
private var device: MTLDevice
private var commandQueue: MTLCommandQueue
init() {
guard let device = MTLCreateSystemDefaultDevice(),
let commandQueue = device.makeCommandQueue() else {
fatalError("Metal not supported")
}
self.device = device
self.commandQueue = commandQueue
}
func applyImageFilter(to texture: MTLTexture) -> MTLTexture? {
let descriptor = MTLTextureDescriptor.texture2DDescriptor(
pixelFormat: .rgba8Unorm,
width: texture.width,
height: texture.height,
mipmapped: false
)
guard let outputTexture = device.makeTexture(descriptor: descriptor),
let commandBuffer = commandQueue.makeCommandBuffer() else {
return nil
}
let filter = MPSImageGaussianBlur(device: device, sigma: 2.0)
filter.encode(
commandBuffer: commandBuffer,
sourceTexture: texture,
destinationTexture: outputTexture
)
commandBuffer.commit()
commandBuffer.waitUntilCompleted()
return outputTexture
}
}
Flutter FPS Optimization
Widget Build Optimization
dart
class OptimizedWidget extends StatefulWidget {
@override
_OptimizedWidgetState createState() => _OptimizedWidgetState();
}
class _OptimizedWidgetState extends State<OptimizedWidget> {
@override
Widget build(BuildContext context) {
return RepaintBoundary(
child: AnimatedBuilder(
animation: animationController,
builder: (context, child) {
return Transform.translate(
offset: Offset(animation.value * 200, 0),
child: child,
);
},
child: ExpensiveWidget(), // This won't rebuild every frame
),
);
}
}
Skia Engine Optimization
dart
class CustomPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
// Use efficient drawing operations
final paint = Paint()
..color = Colors.blue
..style = PaintingStyle.fill;
// Batch drawing operations
final path = Path()
..moveTo(0, 0)
..lineTo(size.width, 0)
..lineTo(size.width, size.height)
..close();
canvas.drawPath(path, paint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
// Only repaint when necessary
return false;
}
}
Animation Performance Optimization
High-Performance Animation Techniques
Property Animation Optimization
kotlin
// Android - Use ValueAnimator for custom animations
class CustomAnimator {
fun createOptimizedAnimation(view: View): ValueAnimator {
return ValueAnimator.ofFloat(0f, 1f).apply {
duration = 300
interpolator = AccelerateDecelerateInterpolator()
addUpdateListener { animator ->
val progress = animator.animatedValue as Float
view.translationX = progress * 200f
view.alpha = progress
}
}
}
}
swift
// iOS - Use UIViewPropertyAnimator for modern animations
class AnimationController {
func createOptimizedAnimation(for view: UIView) {
let animator = UIViewPropertyAnimator(
duration: 0.3,
curve: .easeInOut
) {
view.transform = CGAffineTransform(translationX: 200, y: 0)
view.alpha = 1.0
}
animator.startAnimation()
}
}
Composite Layer Optimization
Layer Promotion Strategies
kotlin
// Android - Hardware layer for animations
class LayerOptimizedView : View {
fun startOptimizedAnimation() {
// Promote to hardware layer during animation
setLayerType(LAYER_TYPE_HARDWARE, null)
animate()
.translationX(200f)
.setDuration(300)
.withEndAction {
// Remove hardware layer after animation
setLayerType(LAYER_TYPE_NONE, null)
}
.start()
}
}
swift
// iOS - CALayer optimization
extension UIView {
func performLayerOptimizedAnimation() {
// Enable rasterization during animation
layer.shouldRasterize = true
layer.rasterizationScale = UIScreen.main.scale
UIView.animate(
withDuration: 0.3,
animations: {
self.transform = CGAffineTransform(translationX: 200, y: 0)
},
completion: { _ in
// Disable rasterization after animation
self.layer.shouldRasterize = false
}
)
}
}
Performance Profiling and Monitoring
Frame Rate Monitoring Tools
Real-time Performance Tracking
kotlin
// Android - Custom FPS counter
class FPSCounter {
private var frameCount = 0
private var lastTime = System.currentTimeMillis()
fun onFrame() {
frameCount++
val currentTime = System.currentTimeMillis()
if (currentTime - lastTime >= 1000) {
val fps = frameCount * 1000f / (currentTime - lastTime)
Log.d("FPS", "Current FPS: $fps")
frameCount = 0
lastTime = currentTime
}
}
}
swift
// iOS - CADisplayLink for FPS monitoring
class FPSMonitor {
private var displayLink: CADisplayLink?
private var lastTimestamp: CFTimeInterval = 0
private var frameCount = 0
func startMonitoring() {
displayLink = CADisplayLink(target: self, selector: #selector(displayLinkFired))
displayLink?.add(to: .main, forMode: .common)
}
@objc private func displayLinkFired(_ displayLink: CADisplayLink) {
if lastTimestamp == 0 {
lastTimestamp = displayLink.timestamp
return
}
frameCount += 1
let elapsed = displayLink.timestamp - lastTimestamp
if elapsed >= 1.0 {
let fps = Double(frameCount) / elapsed
print("Current FPS: \(fps)")
frameCount = 0
lastTimestamp = displayLink.timestamp
}
}
}
Performance Optimization Best Practices
Animation Performance Guidelines
- Use appropriate animation properties: Transform, opacity, and other GPU-accelerated properties
- Avoid layout thrashing: Don't animate properties that trigger layout recalculation
- Batch animations: Group multiple animations together when possible
- Use easing functions: Provide natural motion with proper timing curves
Memory and CPU Optimization
dart
// Flutter - Efficient animation disposal
class AnimationController extends StatefulWidget {
@override
_AnimationControllerState createState() => _AnimationControllerState();
}
class _AnimationControllerState extends State<AnimationController>
with TickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(milliseconds: 300),
vsync: this,
);
_animation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
));
}
@override
void dispose() {
_controller.dispose(); // Important: Dispose to prevent memory leaks
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Opacity(
opacity: _animation.value,
child: child,
);
},
child: Container(
width: 100,
height: 100,
color: Colors.blue,
),
);
}
}
Advanced FPS Optimization Techniques
Render Pipeline Optimization
GPU Utilization Strategies
kotlin
// Android - Custom drawable for GPU optimization
class GPUOptimizedDrawable : Drawable() {
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
override fun draw(canvas: Canvas) {
// Use hardware-accelerated drawing operations
canvas.drawRect(bounds, paint)
}
override fun setAlpha(alpha: Int) {
paint.alpha = alpha
}
override fun setColorFilter(colorFilter: ColorFilter?) {
paint.colorFilter = colorFilter
}
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
}
Cross-Platform Performance Strategies
React Native FPS Optimization
javascript
// React Native - Optimized animations
import { Animated, useNativeDriver } from 'react-native';
const OptimizedAnimation = () => {
const animatedValue = useRef(new Animated.Value(0)).current;
const startAnimation = () => {
Animated.timing(animatedValue, {
toValue: 1,
duration: 300,
useNativeDriver: true, // Critical for performance
}).start();
};
return (
<Animated.View
style={{
transform: [{
translateX: animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [0, 200],
}),
}],
}}
>
{/* Content */}
</Animated.View>
);
};
This comprehensive guide covers FPS optimization techniques across all major mobile platforms, providing practical implementation examples and performance monitoring strategies for maintaining smooth 60+ FPS performance in mobile applications.