Open In App

AnimatedWidget flutter

Last Updated : 07 Jun, 2025
Summarize
Comments
Improve
Suggest changes
Share
Like Article
Like
Report

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.

What is AnimatedWidget 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.

Understanding the 'AnimatedWidget' Class

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.

Steps to Build a Custom Animated Widget in Flutter

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
    );
  }
}

Step 3: Create the AnimatedWidget

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.

Example 2:

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:


Next Article

Similar Reads