In Flutter, creating these visually attractive and smooth Animations can be a challenging task, as everything in Flutter is a Widget, and requires strong control over the widget state and transitions. For that, we have the "AnimatedWidget" class in Flutter.
'AnimatedWidget' is a powerful class in Flutter's animation framework that is used to simplify the implementation of animations in Mobile Apps. They are used with Animation objects, which are Listenable, although they can be used with any listenable, including ValueNotifier and ChangeNotifier. AnimatedWidget is particularly valuable for stateless widgets that need animation capabilities. By using this, developers can create dynamic and responsive UI elements that respond when the user interacts with them, in real-time, improving the aesthetic appeal of the app but also providing an enjoyable and fun experience.
The AnimatedWidget isn't exactly a widget but an abstract class, but it is a powerful tool from which we can create our animations. There are some built-in animated widgets already built for you, like SizeTransition, RotationTransition, ButtonTransition, etc. We can also make our custom animations if we want.
Step 1: Create a new Flutter Application
Create a new Flutter application using the command Prompt. To create a new app, write the following command and run it.
flutter create app_name
To know more about it refer this article: Creating a Simple Application in Flutter
Step 2: Create the Main App
Create the main entry point for your Flutter application:
Dart
// Importing the Flutter material library for UI components
import 'package:flutter/material.dart';
// Entry point of the application
void main() {
runApp(MyApp()); // Runs the root widget of the app
}
// Root widget of the application
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'AnimatedWidget Example', // Title of the app (used by OS)
theme: ThemeData(
primarySwatch: Colors.green, // Set green as the primary color theme
),
debugShowCheckedModeBanner: false, // Removes the debug banner in UI
home: MyHomePage(), // Sets the main screen of the app
);
}
}
Create a custom AnimatedWidget to handle the color animation.
Dart
// Custom widget that extends AnimatedWidget to animate a color transition
class ColorTransition extends AnimatedWidget {
// Constructor that accepts the color animation
ColorTransition({Key? key, required Animation<Color?> animation})
: super(key: key, listenable: animation); // Set animation as the listenable
@override
Widget build(BuildContext context) {
// Cast the listenable to Animation<Color?>
final animation = listenable as Animation<Color?>;
// Return a container whose background color changes based on the animation
return Container(
height: 100, // Fixed height
width: 100, // Fixed width
color: animation.value, // Animated background color
);
}
}
Step 4: Implement the Home Page with Animation
Implement the MyHomePage widget to control the animation and handle the button click.
Dart
// A StatefulWidget to manage animation state
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState(); // Creates the state object
}
// State class for MyHomePage with ticker support for animation
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
late AnimationController _controller; // Controls the animation timeline
late Animation<Color?> _animation; // Animates a color transition
bool _isAnimating = false; // Tracks whether animation is running
@override
void initState() {
super.initState(); // Call to parent method to initialize state
// Initialize the animation controller with 1-second duration
_controller = AnimationController(
duration: const Duration(seconds: 1), // Total animation time
vsync: this, // Provides a ticker to optimize performance
);
// Create a color tween animation from green to blue
_animation = ColorTween(
begin: Colors.green, // Start color
end: Colors.blue, // End color
).animate(_controller); // Animate the tween using the controller
}
// Handles the button click to start or reverse the animation
void _handleClick() {
if (_isAnimating) {
_controller.reverse(); // Reverse the animation if already running
} else {
_controller.forward(); // Start the animation forward if not running
}
_isAnimating = !_isAnimating; // Toggle the animation state
}
@override
void dispose() {
_controller.dispose(); // Dispose the animation controller to free resources
super.dispose(); // Call to parent method to clean up
}
@override
Widget build(BuildContext context) {
return Scaffold(
// App bar with title and styling
appBar: AppBar(
title: const Text('GeeksForGeeks Animations'), // App bar title
backgroundColor: Colors.green, // App bar background color
foregroundColor: Colors.white, // Title and icon color
),
// Body of the Scaffold
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center, // Center the children vertically
children: [
// Custom animated widget that uses the color animation
ColorTransition(animation: _animation),
SizedBox(height: 20), // Add vertical spacing
// Button to trigger animation
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green, // Button background color
foregroundColor: Colors.white, // Button text color
),
onPressed: _handleClick, // Call function on button press
child: Text('Click Me'), // Button label
),
],
),
),
);
}
}
Complete Source Code
main.dart:
main.dart
// Importing the Flutter material library for UI components
import 'package:flutter/material.dart';
// Entry point of the application
void main() {
runApp(MyApp()); // Runs the root widget of the app
}
// Root widget of the application
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'AnimatedWidget Example', // Title of the app (used by OS)
theme: ThemeData(
primarySwatch: Colors.green, // Set green as the primary color theme
),
debugShowCheckedModeBanner: false, // Removes the debug banner in UI
home: MyHomePage(), // Sets the main screen of the app
);
}
}
// A StatefulWidget to manage animation state
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState(); // Creates the state object
}
// State class for MyHomePage with ticker support for animation
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
late AnimationController _controller; // Controls the animation timeline
late Animation<Color?> _animation; // Animates a color transition
bool _isAnimating = false; // Tracks whether animation is running
@override
void initState() {
super.initState(); // Call to parent method to initialize state
// Initialize the animation controller with 1-second duration
_controller = AnimationController(
duration: const Duration(seconds: 1), // Total animation time
vsync: this, // Provides a ticker to optimize performance
);
// Create a color tween animation from green to blue
_animation = ColorTween(
begin: Colors.green, // Start color
end: Colors.blue, // End color
).animate(_controller); // Animate the tween using the controller
}
// Handles the button click to start or reverse the animation
void _handleClick() {
if (_isAnimating) {
_controller.reverse(); // Reverse the animation if already running
} else {
_controller.forward(); // Start the animation forward if not running
}
_isAnimating = !_isAnimating; // Toggle the animation state
}
@override
void dispose() {
_controller.dispose(); // Dispose the animation controller to free resources
super.dispose(); // Call to parent method to clean up
}
@override
Widget build(BuildContext context) {
return Scaffold(
// App bar with title and styling
appBar: AppBar(
title: const Text('GeeksForGeeks Animations'), // App bar title
backgroundColor: Colors.green, // App bar background color
foregroundColor: Colors.white, // Title and icon color
),
// Body of the Scaffold
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center, // Center the children vertically
children: [
// Custom animated widget that uses the color animation
ColorTransition(animation: _animation),
SizedBox(height: 20), // Add vertical spacing
// Button to trigger animation
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green, // Button background color
foregroundColor: Colors.white, // Button text color
),
onPressed: _handleClick, // Call function on button press
child: Text('Click Me'), // Button label
),
],
),
),
);
}
}
// Custom widget that extends AnimatedWidget to animate a color transition
class ColorTransition extends AnimatedWidget {
// Constructor that accepts the color animation
ColorTransition({Key? key, required Animation<Color?> animation})
: super(key: key, listenable: animation); // Set animation as the listenable
@override
Widget build(BuildContext context) {
// Cast the listenable to Animation<Color?>
final animation = listenable as Animation<Color?>;
// Return a container whose background color changes based on the animation
return Container(
height: 100, // Fixed height
width: 100, // Fixed width
color: animation.value, // Animated background color
);
}
}
And when we click the Click Me button, the container color will change to blue and back to green, creating a simple but effective color animation.
Output:
Now let's add to this color transition and also increase the size in the next animation example.
Let's create another simple example where a "Click Me" button triggers an animation of a container changing both its color and size as well
Step 1: Importing Packages
First, we import the necessary Flutter material package:
import 'package:flutter/material.dart';
Step 2: Create the Main app
Add the main entry point for your Flutter application:
Dart
// Entry point of the Flutter application
void main() {
runApp(MyApp()); // Launches the app by calling the root widget
}
// The root widget of the app
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'GeeksforGeeks AnimatedWidget Example', // Title for the application
theme: ThemeData(primarySwatch: Colors.green), // Sets a green color theme
debugShowCheckedModeBanner: false, // Hides the debug banner on top right
home: MyHomePage(), // Sets the home screen to MyHomePage widget
);
}
}
Step 3: Set up the Animation:
Configuring the color and size of animations for the MyHomePage widget :
Dart
// A stateful widget to manage and control animation
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState(); // Creates the mutable state
}
// The state class with animation controller and logic
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
late AnimationController _controller; // Controls the animation timing
late Animation<double> _animation; // Defines the animated value (double type)
@override
void initState() {
super.initState(); // Calls the parent's initState
// Initializes the animation controller with 2-second duration
_controller = AnimationController(
duration: const Duration(seconds: 2), // Animation will last 2 seconds
vsync: this, // Provides a ticker to sync animation with screen refresh
);
// Defines an animation that interpolates between 100 and 200
_animation = Tween<double>(begin: 100, end: 200).animate(_controller);
}
@override
void dispose() {
_controller.dispose(); // Frees animation controller resources
super.dispose(); // Calls parent class dispose
}
// Handles button press to toggle animation forward and reverse
void _startAnimation() {
if (_controller.isAnimating) {
_controller.reverse(); // Reverses animation if it is already playing
} else {
_controller.forward(); // Starts animation forward
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
// Top bar of the screen
appBar: AppBar(
backgroundColor: Colors.green, // Background color of AppBar
foregroundColor: Colors.white, // Title and icon color
title: const Text('GeeksforGeeks Animations'), // Title of AppBar
),
// Body section of the screen
body: Center(
// Aligns children vertically and centers them
child: Column(
mainAxisAlignment: MainAxisAlignment.center, // Center vertically
children: [
// Custom animated widget that animates size and color
ColorSizeAnimation(animation: _animation),
SizedBox(height: 20), // Adds vertical spacing
// A button that triggers the animation
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green, // Button background color
foregroundColor: Colors.white, // Text color
),
onPressed: _startAnimation, // Calls function on button tap
child: Text('Click Me'), // Button text
),
],
),
),
);
}
}
Step 4: Implement the HomePage with Animations
Configuring color and size animations with the “HomePage” widget
Dart
// A stateful widget to manage and control animation
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState(); // Creates the mutable state
}
// The state class with animation controller and logic
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
late AnimationController _controller; // Controls the animation timing
late Animation<double> _animation; // Defines the animated value (double type)
@override
void initState() {
super.initState(); // Calls the parent's initState
// Initializes the animation controller with 2-second duration
_controller = AnimationController(
duration: const Duration(seconds: 2), // Animation will last 2 seconds
vsync: this, // Provides a ticker to sync animation with screen refresh
);
// Defines an animation that interpolates between 100 and 200
_animation = Tween<double>(begin: 100, end: 200).animate(_controller);
}
@override
void dispose() {
_controller.dispose(); // Frees animation controller resources
super.dispose(); // Calls parent class dispose
}
// Handles button press to toggle animation forward and reverse
void _startAnimation() {
if (_controller.isAnimating) {
_controller.reverse(); // Reverses animation if it is already playing
} else {
_controller.forward(); // Starts animation forward
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
// Top bar of the screen
appBar: AppBar(
backgroundColor: Colors.green, // Background color of AppBar
foregroundColor: Colors.white, // Title and icon color
title: const Text('GeeksforGeeks Animations'), // Title of AppBar
),
// Body section of the screen
body: Center(
// Aligns children vertically and centers them
child: Column(
mainAxisAlignment: MainAxisAlignment.center, // Center vertically
children: [
// Custom animated widget that animates size and color
ColorSizeAnimation(animation: _animation),
SizedBox(height: 20), // Adds vertical spacing
// A button that triggers the animation
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green, // Button background color
foregroundColor: Colors.white, // Text color
),
onPressed: _startAnimation, // Calls function on button tap
child: Text('Click Me'), // Button text
),
],
),
),
);
}
}
Complete Source Code
main.dart:
main.dart
// Importing Flutter's material design library
import 'package:flutter/material.dart';
// Entry point of the Flutter application
void main() {
runApp(MyApp()); // Launches the app by calling the root widget
}
// The root widget of the app
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'GeeksforGeeks AnimatedWidget Example', // Title for the application
theme: ThemeData(primarySwatch: Colors.green), // Sets a green color theme
debugShowCheckedModeBanner: false, // Hides the debug banner on top right
home: MyHomePage(), // Sets the home screen to MyHomePage widget
);
}
}
// A stateful widget to manage and control animation
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState(); // Creates the mutable state
}
// The state class with animation controller and logic
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
late AnimationController _controller; // Controls the animation timing
late Animation<double> _animation; // Defines the animated value (double type)
@override
void initState() {
super.initState(); // Calls the parent's initState
// Initializes the animation controller with 2-second duration
_controller = AnimationController(
duration: const Duration(seconds: 2), // Animation will last 2 seconds
vsync: this, // Provides a ticker to sync animation with screen refresh
);
// Defines an animation that interpolates between 100 and 200
_animation = Tween<double>(begin: 100, end: 200).animate(_controller);
}
@override
void dispose() {
_controller.dispose(); // Frees animation controller resources
super.dispose(); // Calls parent class dispose
}
// Handles button press to toggle animation forward and reverse
void _startAnimation() {
if (_controller.isAnimating) {
_controller.reverse(); // Reverses animation if it is already playing
} else {
_controller.forward(); // Starts animation forward
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
// Top bar of the screen
appBar: AppBar(
backgroundColor: Colors.green, // Background color of AppBar
foregroundColor: Colors.white, // Title and icon color
title: const Text('GeeksforGeeks Animations'), // Title of AppBar
),
// Body section of the screen
body: Center(
// Aligns children vertically and centers them
child: Column(
mainAxisAlignment: MainAxisAlignment.center, // Center vertically
children: [
// Custom animated widget that animates size and color
ColorSizeAnimation(animation: _animation),
SizedBox(height: 20), // Adds vertical spacing
// A button that triggers the animation
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green, // Button background color
foregroundColor: Colors.white, // Text color
),
onPressed: _startAnimation, // Calls function on button tap
child: Text('Click Me'), // Button text
),
],
),
),
);
}
}
// Custom widget that animates both color and size using AnimatedWidget
class ColorSizeAnimation extends AnimatedWidget {
// Constructor takes an animation and sets it as the listenable
ColorSizeAnimation({Key? key, required Animation<double> animation})
: super(key: key, listenable: animation);
@override
Widget build(BuildContext context) {
// Cast the listenable to Animation<double> type
final animation = listenable as Animation<double>;
return Container(
height: animation.value, // Sets height based on animation
width: animation.value, // Sets width based on animation
// Interpolates color between green and blue based on current animation value
color: Color.lerp(Colors.green, Colors.blue, animation.value / 200),
);
}
}
When you run the above code, you will see a green container in the center of the screen. When you click the "Click Me" button, the container will smoothly transition in size and color, creating an engaging and dynamic animation.
Output: