Flutter development offers a rich avenue for implementing animations in applications. When discussing animations in Flutter, the useAnimationController class is pivotal in making that happen. The primary task of the useAnimationController is to manage the animation progress for widgets, making them dynamic and interactive.
The role of useAnimationController in Flutter application development cannot be understated. It is the key to creating interesting and immersive animation experiences. For new developers or seasoned professionals looking to add an extra layer of polish to their applications, understanding the useAnimationController class can boost the expressiveness of application interfaces.
In this tutorial, we will cover the basics of animations and the useAnimationController class. The primary aim of the current tutorial is to show how to make the best out of the useAnimationController in your Flutter projects.
Animations breathe life into applications. They give users a smooth, interactive experience, attracting and retaining their attention. To create animations in Flutter, understanding AnimationController is crucial.
In Flutter, an Animation is an object that generates new values over a certain Duration. The AnimationController class, an Animation<double>
, is a special type of Animation that can directly control the animation's progress. It provides methods to play forward, reverse, or stop the animation. This makes it one of the most important components of the Flutter animation library.
The AnimationController class is a base class typed with double and extends Animation<double>
. Each controller has a Duration and various listeners that can be added, all to manipulate the current value of the animation object. The AnimationController generates a new value every time Flutter requests a new frame, typically 60 times per second.
The AnimationController class is generally used with a TickerProvider class in Flutter. Whenever a new value needs to be generated (in response to a tick function), the animation controller uses the TickerProvider. The TickerProvider creates a Ticker each time the 'createTickerfunction is called. TheTicker calls its callback method once per animation frame, which helps control the animation.
Here is a basic example of how to define a controller within a StatefulWidget:
1AnimationController controller; 2 3@override 4void initState() { 5 super.initState(); 6 controller = AnimationController( 7 duration: const Duration(seconds: 2), 8 vsync: this, 9 ); 10} 11 12@override 13void dispose() { 14 controller.dispose(); 15 super.dispose(); 16}
As we go deeper in this tutorial, we will understand more about the AnimationController class and, importantly, the useAnimationController hook.
The useAnimationController class of Flutter is an alternate approach to using AnimationController. Remi Rousselet's flutter_hooks package introduced it.
To minimize the boilerplate code often associated with animations in a StatefulWidget, We can employ the useAnimationController, a hook from the Flutter hooks package. Simply put, hooks are function components that can utilize stateful behavior inside StatelessWidget, thereby reducing the amount of code and increasing efficiency.
The useAnimationController hook in Flutter grants developers more control over animations, alleviating the need to persist the AnimationController instance.
As an example, here's a simple function component with useAnimationController in action:
1import 'package:flutter_hooks/flutter_hooks.dart'; 2 3Widget buildAnimation({Key key}) { 4 final controller = useAnimationController(duration: const Duration(seconds: 2)); 5 return Container(); 6}
As seen here, the useAnimationController function takes an unnamed argument and duration and returns an instance of AnimationController that has been created and will be automatically cleaned up when the widget is unmounted.
useAnimationController creates the AnimationController during the first call of the build method of the widget in which it resides.
Notice that the controller is defined upfront. Subsequent builds do not recreate it, rather, the original is used. This optimizes memory and state management.
One important note on useAnimationController is that the hook does not implicitly initiate the animation. You must explicitly call animation.forward() or animation.reverse() to start the animation.
This useAnimationController example showcases how easy it is to manipulate duration and control animations- all with the ease of using hooks!
By doing away with the StatefulWidget, you can inject animations directly into the widget tree. This boosts code readability and maintains your widget immutability.
Utilizing useAnimationController in your Flutter projects can yield tremendous boons.
Firstly, it simplifies the management of the AnimationController lifecycle. Usually, in a StatefulWidget, you need to create an AnimationController in your initState function and then dispose of it in your dispose function. Forget to dispose of it, and you've got a memory leak. useAnimationController, however, effortlessly manages this cycle. As it's linked to StatefulWidget lifecycle hooks, it automatically initializes the AnimationController on the first call and disposes of it when it is discarded from the widget tree.
Here is a snippet showing how you can use useAnimationController:
1Widget build(BuildContext context) { 2 final controller = useAnimationController(duration: Duration(seconds: 1)); 3 return Container(child: AnimationLogo(animation: controller)); 4}
In this code, the animation object is created during the first call of the build function with the instance of AnimationController. AnimationLogo is a Stateless widget that will receive the Animation object, controller, as a parameter.
A second major boon is increased code efficiency. Bypassing the StatelessWidget in favor of using hooks reduces boilerplate, increases code reusability and make the code subtler and simpler to understand. Creating complex animations without cluttering your widget build produces cleaner, more efficient Flutter code.
Ultimately, more streamlined code leads to less debugging down the line.
The value of adopting useAnimationController cannot be overstated. With better lifecycle management, cleaner code, and increased maintainability, useAnimationController paints your animation code in a new, brilliant light.
Before we embark on more practical examples of useAnimationController in our Flutter application, let's ensure our development environment is properly set up.
Start by creating a new Flutter project.
1flutter create useanimationcontroller_example
Navigate into your newly created Flutter project.
1cd useanimationcontroller_example
Open your pubspec.yaml file and add the flutter_hooks package:
1dependencies: 2 flutter_hooks: ^0.22.0
Run 'pub get' to fetch the new package.
1flutter pub get
Now, we are ready to proceed with sample practical examples of using the useAnimationController class in our Flutter application. The flutter_hooks package is now available for use along with the useAnimationController hook.
The code for your main file should look something like this:
1import 'package:flutter/material.dart'; 2import 'package:flutter_hooks/flutter_hooks.dart'; 3 4void main() { 5 runApp(MyApp()); 6} 7 8class MyApp extends StatelessWidget { 9 @override 10 Widget build(BuildContext context) { 11 return MaterialApp( 12 home: HomeScreen(), 13 ); 14 } 15} 16 17class HomeScreen extends HookWidget { 18 @override 19 Widget build(BuildContext context) { 20 // We'll start putting our Animation Controller here! 21 // ... 22 return Scaffold( 23 appBar: AppBar( 24 title: Text('useAnimationController Example'), 25 ), 26 ); 27 } 28}
In the next part, we will dive into some practical applications of useAnimationController.
Now that our development environment is set up, it's time to begin applying our knowledge of useAnimationController. Remember, all this happens within the HookWidget.
First, we will define the controller within the build method using useAnimationController, and then define the animation.
1Widget build(BuildContext context) { 2 final controller = useAnimationController(duration: Duration(seconds: 1)); 3 final animation = CurvedAnimation(parent: controller, curve: Curves.easeIn); 4 5 return Container(); 6}
Note here that we define an Animation<double>
that progresses over 1 second and applies an easing curve via the curve parameter.
To play the animation on a loop indefinitely, you can use the repeat method as such:
1Widget build(BuildContext context) { 2 final controller = useAnimationController(duration: Duration(seconds: 1)); 3 final animation = CurvedAnimation(parent: controller, curve: Curves.easeIn); 4 5 useEffect(() { 6 controller.repeat(); 7 return controller.dispose; 8 }, []); 9 10 return Container(); 11}
In the above useEffect function, the first parameter is a callback function that starts the animation. The callback will be triggered after the widget build method is called for the first time. The callback also disposes of the controller when not needed.
Next, let's add an AnimatedBuilder widget that will perform our animation. We add this into the return of our build method:
1return AnimatedBuilder( 2 animation: controller, 3 builder: (BuildContext context, _){ 4 return Center( 5 child: Container( 6 width: 200.0 + (controller.value * 100), 7 height: 200.0 + (controller.value * 100), 8 color: Colors.blue, 9 ), 10 ); 11 }, 12);
In this Flutter useAnimationController example, AnimatedBuilder listens to changes in our AnimationController's value and triggers a rebuild of the builder function. The builder function creates a Container whose size changes based on the current AnimationController's value multiplied by 100.
Our final build function will look like this:
1@override 2Widget build(BuildContext context) { 3 final controller = useAnimationController(duration: const Duration(seconds: 2)); 4 final animation = CurvedAnimation(parent: controller, curve: Curves.easeIn); 5 6 // Start the animation 7 useEffect(() { 8 controller.repeat(); 9 return controller.dispose; 10 }, const []); 11 12 return AnimatedBuilder( 13 animation: controller, 14 builder: (BuildContext context, _) { 15 return Center( 16 child: Container( 17 width: 200.0 + (controller.value * 100), 18 height: 200.0 + (controller.value * 100), 19 color: Colors.blue, 20 ), 21 ); 22 }, 23 ); 24}
This is a simple Flutter useAnimationController example, but it should provide a good introduction to animations in Flutter. For additional information on more complex use cases, reading the official Flutter documentation on animations can help.
With a firm grasp of the basics, we can dive into the advanced features of the useAnimationController class in Flutter, which allow you to create more complex animations.
1@override 2Widget build(BuildContext context) { 3 final controller = useAnimationController(duration: const Duration(seconds: 2)); 4 final secondAnimationController = useAnimationController(duration: const Duration(seconds: 1)); 5 6 useEffect(() { 7 Future.delayed(Duration(milliseconds: 500), () { 8 secondAnimationController.repeat(reverse: true); 9 }); 10 controller.repeat(reverse: true); 11 return () { 12 controller.dispose(); 13 secondAnimationController.dispose(); 14 }; 15 }, const []); 16 17 return Stack( 18 children: <Widget>[ 19 buildAnimation(controller), 20 buildSecondAnimation(secondAnimationController), 21 ], 22 ); 23}
In the example above, we've created a second AnimationController which starts 500ms after the first AnimationController. We then place the widgets returned from buildAnimation and buildSecondAnimation in a Stack widget, which overlays the children's widgets on top of each other. The net result is two animations running simultaneously at staggered intervals.
Exploring these advanced features, we find that useAnimationController opens the gates to a new world of expressiveness and dynamism in Flutter application development.
With the expansive functionality the useAnimationController class brings, there are a few pitfalls developers may encounter. Being aware of common errors and adhering to best practices can save much time during debugging.
1. Forgetting to dispose of the AnimationController: Forgetting to clean up after using AnimationController can lead to memory leaks in the app. However, with the useAnimationController hook, this is managed automatically.
2. Neglecting to check the current status of the animation: Trying to restart an already running AnimationController can trigger a Tickeractive error. Always check the current status of the animation before starting or stopping it.
3. Illogical sequence of keyframes in the animation: This can lead to sudden jumps or stops, disrupting the smooth experience.
Here's a simple best practice example:
1Widget buildAnimation(AnimationController controller) { 2 return AnimatedBuilder( 3 animation: controller, 4 builder: (BuildContext context, _) { 5 return Container( 6 width: 200.0 + (controller.value * 100), 7 height: 200.0 + (controller.value * 100), 8 color: Colors.blue, 9 ); 10 }, 11 ); 12}
By following these strategies, you can avoid common errors and adhere to best practices, making your journey with useAnimationController smoother.
Throughout this tutorial, we've unlocked the power of useAnimationController in Flutter, taken strides from understanding the basics, and ventured into some advanced features this class offers.
The primary benefits of useAnimationController are outstanding control over animations, cleaner code, and seamless lifecycle management, making it a beneficial tool when crafting animations in your Flutter applications.
Adopting useAnimationController is a great way to boost your Flutter applications' functionality, user interactivity, and visual appeal.
As always, good luck and happy coding. Keep exploring and innovating!
Here are a few resources that were referenced throughout this blog to provide a deeper understanding:
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.