Boosting Flutter Performance with Frame-Based Rendering using

Boosting Flutter Performance with Frame-Based Rendering using keframe

Flutter is known for its smooth UI performance, but complex animations or frequent rebuilds can sometimes lead to jank. Frame-based rendering, also known as keyframe animation, offers a powerful technique to optimize these scenarios. This article explores how to leverage frame-based rendering in Flutter using the keframe package, focusing on FrameAnimation, FrameSeparateWidget, and SizeCacheWidget.

What is Frame-Based Rendering?

Traditional rendering in Flutter often involves rebuilding widgets every time their properties change. While efficient in many cases, this can become a bottleneck when dealing with intricate animations or rapidly changing data.

Frame-based rendering pre-calculates animation frames and stores them. During animation, the system displays these pre-rendered frames sequentially, minimizing constant rebuilds. This results in smoother animations and improved performance, especially on less powerful devices.

Introducing keframe

The keframe package simplifies frame-based rendering in Flutter. It provides widgets and utilities to define keyframes and animate between them efficiently.

1
2
dependencies:
keframe: ^2.0.6

Core Components: FrameAnimation, FrameSeparateWidget, and SizeCacheWidget
keframe provides three main components that work together:

  • FrameAnimation: The core widget that manages the animation timeline and displays the pre-rendered frames.
  • FrameSeparateWidget: This widget is crucial for separating the frame building process from the animation rendering. It ensures that frames are built only once and cached.
  • SizeCacheWidget: This widget caches the size of the child widget. This is important because layout calculations can be expensive, and caching the size prevents unnecessary re-layouts during animation.

Basic Usage with All Components

Here’s an example demonstrating how to use all three components to animate a widget’s opacity and size:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import 'package:flutter/material.dart';
import 'package:keframe/keframe.dart';

class ComplexAnimation extends StatefulWidget {
const ComplexAnimation({super.key});

@override
State<ComplexAnimation> createState() => _ComplexAnimationState();
}

class _ComplexAnimationState extends State<ComplexAnimation> {
double size = 100;

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Complex Animation')),
body: Center(
child: GestureDetector(
onTap: () {
setState(() {
size = size == 100 ? 200 : 100;
});
},
child: FrameAnimation(
frameLen: 2,
duration: const Duration(milliseconds: 500),
curve: Curves.easeInOut,
frameBuilder: (context, frameIndex) {
return FrameSeparateWidget(
index: frameIndex,
builder: (context) {
return SizeCacheWidget(
child: Opacity(
opacity: frameIndex == 0 ? 0.5 : 1.0,
child: Container(
width: size,
height: size,
color: Colors.blue,
),
),
);
},
);
},
),
),
),
);
}
}

Key improvements in this example:

  • FrameSeparateWidget is used: This ensures the frame is built only once for each frame index.
  • SizeCacheWidget is used: This caches the size of the container, preventing unnecessary re-layouts.
  • Combined opacity and size animation: Demonstrates animating multiple properties.

Explanation

  1. The FrameAnimation widget manages the animation timeline and calls the frameBuilder for each frame.
  2. The FrameSeparateWidget receives the frameIndex and uses it as a key to cache the built widget. This is the core of the frame-based rendering optimization.
  3. The SizeCacheWidget wraps the animated widget and caches its size, preventing unnecessary re-layouts.

Benefits of Using keframe

  • Improved Performance: By pre-rendering and caching frames and sizes, keframe significantly reduces the computational load during animation, leading to smoother performance, especially on lower-end devices and complex animations.
  • Simplified Complex Animations: keframe provides a clean and concise way to define complex animations with multiple stages and properties.
  • Reduced Jank: Frame-based rendering helps minimize jank, resulting in a more polished user experience.

Conclusion

keframe, with its FrameAnimation, FrameSeparateWidget, and SizeCacheWidget components, provides a powerful and efficient way to optimize Flutter applications, especially when dealing with complex animations. By using frame-based rendering, you can significantly improve performance and create smoother user experiences.

Further Exploration

keframe package on pub.dev