Flutter code creating laggy animation. What is wrong here?
The whole purpose of using AnimationController
is to listen to its events - that's what AnimatedBuilder
does and rebuilds its subtree accordingly.
I will post here my overall recommendations on what to change in the code.
Remove setState
- that's what makes your entire layout rebuild all over again, i.e. lags.
Also trigger _animeController
listeners, i.e. AnimatedBuilder in your case - to rebuild itself.
accelerometerEvents.listen((AccelerometerEvent event) {
var a = ((event.x * 100).round() / 100).clamp(-1.0, 1.0) * -1;
var b = ((event.y * 100).round() / 100).clamp(-1.0, 1.0);
if ((x - a).abs() > 0.02 || (y - b).abs() > 0.02) {
x = a; y = b;
_animeController.value = _animeController.value; // Trigger controller's listeners
}
});
Start animation in initState
, instead of build
. This is the second thing that produces lags in your case. .forward
triggers rebuild of your widgets, which leads to an infinite loop.
@override
void initState() {
super.initState();
_animeController.forward();
}
Use child
property of your AnimatedBuilder
to save up resources on rebuilding the avatar block every time. Also I'm not sure what Scaffold
is here for - let's remove it if it's not needed.
AnimatedBuilder(
animation: _animeController,
builder: (context, child) => Transform(
transform: Matrix4.translationValues(_anime.value * width * x, _anime.value * height * y, 0.0),
child: child,
),
child: Center(
child: CircleAvatar(
radius: 15.0,
backgroundColor: Colors.green,
),
),
);
Follow Official Animations Tutorial to master Flutter animations.
Let me know if this helps.
Shikhir Aggarwal
Updated on November 30, 2022Comments
-
Shikhir Aggarwal over 1 year
I have created a flutter widget that moves the circle with accelerometer. It is very laggy as I have to use setState to change the position of the circle when phone is moved. Is there an alternative to creating this?
I have used AnimatedBuilder here but not sure how that can change the position of circle when device is moved smoothly.
class _AnimationWidgetState extends State<AnimationWidget> with TickerProviderStateMixin { AnimationController _animeController; Animation _anime; double x = 0.0, y = 0.0; @override void initState() { super.initState(); _animeController = AnimationController(vsync: this, duration: const Duration(seconds: 2)); _anime = Tween(begin: 0.5, end: 0.5).animate( CurvedAnimation(parent: _animeController, curve: Curves.ease)); accelerometerEvents.listen((AccelerometerEvent event) { var a = ((event.x * 100).round() / 100).clamp(-1.0, 1.0) * -1; var b = ((event.y * 100).round() / 100).clamp(-1.0, 1.0); if ((x - a).abs() > 0.02 || (y - b).abs() > 0.02) { setState(() { x = a; y = b; }); } }); } @override void dispose() { _animeController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { _animeController.forward(); final double width = MediaQuery.of(context).size.width; final double height = MediaQuery.of(context).size.height; return AnimatedBuilder( animation: _animeController, builder: (context, child) { return Scaffold( body: Transform( transform: Matrix4.translationValues( _anime.value * width * x, _anime.value * height * y, 0.0), child: Center( child: CircleAvatar( radius: 15.0, backgroundColor: Colors.green, ), ), ), ); }, ); } }
Animation is not at all smooth. This is because I have to use setState but the movement of circle is working as desired.