Animations can transform your app from functional to delightful. Flutter’s animation system allows you to create smooth, rich, and dynamic visual effects with ease. Whether it’s a subtle fade transition, a bouncing button, or a more complex sequence of animations, Flutter provides a powerful framework to bring your UI to life.
In this tutorial, we’ll dive into the basics of animations in Flutter and cover:
- Implicit animations for simple transitions.
- Explicit animations for more complex control.
- Using the AnimationController for advanced animations.
- Combining multiple animations for more dynamic effects.
Step 1: Using Implicit Animations
Flutter provides a set of implicit animations that make it easy to create simple, smooth transitions without needing an explicit animation controller. These animations automatically handle the transition between two states when a property changes.
1. AnimatedContainer
The AnimatedContainer widget is one of the simplest ways to create an animation. It automatically animates changes to its properties, such as size, color, padding, and more.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _isExpanded = false;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('AnimatedContainer Demo')),
body: Center(
child: GestureDetector(
onTap: () {
setState(() {
_isExpanded = !_isExpanded;
});
},
child: AnimatedContainer(
duration: Duration(seconds: 1),
width: _isExpanded ? 200 : 100,
height: _isExpanded ? 200 : 100,
color: _isExpanded ? Colors.blue : Colors.red,
curve: Curves.easeInOut,
child: Center(child: Text('Tap me')),
),
),
),
),
);
}
}
In this example:
- The AnimatedContainer changes its size and color when the user taps it.
- The
duration
parameter defines how long the animation should take. - The
curve
parameter controls the timing of the animation (e.g., easeInOut for a smooth transition).
2. AnimatedOpacity
To animate the visibility of a widget, you can use AnimatedOpacity. This is useful for fading in or out a widget.
AnimatedOpacity(
opacity: _isVisible ? 1.0 : 0.0,
duration: Duration(seconds: 2),
child: Container(
width: 100,
height: 100,
color: Colors.green,
),
)
This code fades the widget in or out based on the value of _isVisible
.
Step 2: Using Explicit Animations
Implicit animations are great for simple transitions, but when you need more control, explicit animations give you the ability to define custom animation behavior. This involves using an AnimationController and Tween to create complex animations.
1. AnimationController and Tween
The AnimationController is the core building block for explicit animations in Flutter. It allows you to control the animation’s duration, progress, and direction. A Tween defines the range of values over which the animation will interpolate.
Let’s create a simple animation that moves a widget across the screen.
class AnimatedBox extends StatefulWidget {
@override
_AnimatedBoxState createState() => _AnimatedBoxState();
}
class _AnimatedBoxState extends State<AnimatedBox> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<Offset> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(seconds: 2),
vsync: this,
);
_animation = Tween<Offset>(begin: Offset(0, 0), end: Offset(2, 0)).animate(_controller);
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('AnimationController Demo')),
body: SlideTransition(
position: _animation,
child: Container(
width: 100,
height: 100,
color: Colors.blue,
),
),
);
}
}
In this example:
- AnimationController defines the duration and lifecycle of the animation.
- Tween defines the starting and ending positions (from
Offset(0, 0)
toOffset(2, 0)
). - SlideTransition animates the widget’s position using the _animation.
2. Repeating Animations
To create repeating animations, you can use the repeat()
method on the AnimationController.
_controller.repeat(reverse: true);
This will make the animation oscillate back and forth between the start and end values.
Step 3: Combining Multiple Animations
You can combine multiple animations using AnimationControllers and Tweens to create more dynamic effects. Let’s create an animation that changes both the position and size of a widget at the same time.
class MultiAnimationExample extends StatefulWidget {
@override
_MultiAnimationExampleState createState() => _MultiAnimationExampleState();
}
class _MultiAnimationExampleState extends State<MultiAnimationExample> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<Offset> _moveAnimation;
late Animation<double> _sizeAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(seconds: 3),
vsync: this,
);
_moveAnimation = Tween<Offset>(begin: Offset(0, 0), end: Offset(2, 0)).animate(_controller);
_sizeAnimation = Tween<double>(begin: 100, end: 200).animate(_controller);
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Multi Animation')),
body: AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Transform.translate(
offset: _moveAnimation.value,
child: Container(
width: _sizeAnimation.value,
height: _sizeAnimation.value,
color: Colors.orange,
),
);
},
),
);
}
}
- AnimatedBuilder rebuilds the widget tree whenever the animation changes.
- Transform.translate moves the widget, while the container’s width and height are animated using the _sizeAnimation.
Step 4: Animation Curves and Custom Timing
You can adjust how animations progress over time by applying an Animation Curve. Flutter provides a variety of curves like easeIn, bounceOut, and more. You can apply these to your animations to give them different effects.
_animation = Tween<Offset>(begin: Offset(0, 0), end: Offset(2, 0))
.animate(CurvedAnimation(parent: _controller, curve: Curves.bounceOut));
Here, we apply the bounceOut curve to make the movement animation bounce at the end.
Step 5: Hero Animations for Page Transitions
One of the most popular types of animations in Flutter is the Hero animation. It provides a seamless transition between two screens by animating a widget from the first screen to the second.
// First Screen
Hero(
tag: 'hero-example',
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
)
// Second Screen
Hero(
tag: 'hero-example',
child: Container(
width: 200,
height: 200,
color: Colors.red,
),
)
The tag must be the same on both screens, and Flutter will automatically animate the transition between the two widgets.
Conclusion: Bringing Your App to Life with Animations
In this tutorial, we explored different types of animations in Flutter, ranging from simple implicit animations to more complex explicit animations. By using AnimationController, Tween, and Animation Curves, you can create highly dynamic and interactive apps that provide a smooth and engaging user experience.
In the next tutorial, we’ll dive into state management in Flutter and explore how to efficiently manage your app’s state across different widgets and screens. Stay creative, and happy coding!