0
0
Fluttermobile~20 mins

Tween animations in Flutter - Mini App: Build & Ship

Choose your learning style9 modes available
Build: Color Tween Animation
This screen shows a square that smoothly changes its color from blue to red and back repeatedly using a tween animation.
Target UI
┌─────────────────────────────┐
│        Color Tween          │
│                             │
│          ■■■■■■■■           │
│          ■■■■■■■■           │
│          ■■■■■■■■           │
│                             │
│  [Animate Color]             │
└─────────────────────────────┘
A square container of size 150x150 pixels in the center
A button labeled 'Animate Color' below the square
When the button is pressed, the square color animates smoothly from blue to red and back repeatedly
Use Tween animation with AnimationController and ColorTween
Animation should loop continuously until stopped
Button toggles animation start and stop
Starter Code
Flutter
import 'package:flutter/material.dart';

class ColorTweenAnimationScreen extends StatefulWidget {
  @override
  State<ColorTweenAnimationScreen> createState() => _ColorTweenAnimationScreenState();
}

class _ColorTweenAnimationScreenState extends State<ColorTweenAnimationScreen> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<Color?> _colorAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    );

    _colorAnimation = ColorTween(begin: Colors.blue, end: Colors.red).animate(_controller);

    // TODO: Add animation status listener to loop animation
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Color Tween Animation')),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            // TODO: Add AnimatedBuilder to rebuild Container with animated color
            Container(
              width: 150,
              height: 150,
              color: Colors.blue,
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                // TODO: Add button logic to start/stop animation
              },
              child: const Text('Animate Color'),
            ),
          ],
        ),
      ),
    );
  }
}
Task 1
Task 2
Task 3
Solution
Flutter
import 'package:flutter/material.dart';

class ColorTweenAnimationScreen extends StatefulWidget {
  @override
  State<ColorTweenAnimationScreen> createState() => _ColorTweenAnimationScreenState();
}

class _ColorTweenAnimationScreenState extends State<ColorTweenAnimationScreen> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<Color?> _colorAnimation;
  bool isAnimating = false;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    );

    _colorAnimation = ColorTween(begin: Colors.blue, end: Colors.red).animate(_controller);

    _controller.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        _controller.reverse();
      } else if (status == AnimationStatus.dismissed) {
        _controller.forward();
      }
    });
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  void _toggleAnimation() {
    if (isAnimating) {
      _controller.stop();
    } else {
      _controller.forward();
    }
    setState(() {
      isAnimating = !isAnimating;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Color Tween Animation')),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            AnimatedBuilder(
              animation: _colorAnimation,
              builder: (context, child) {
                return Container(
                  width: 150,
                  height: 150,
                  color: _colorAnimation.value,
                );
              },
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: _toggleAnimation,
              child: Text(isAnimating ? 'Stop Animation' : 'Animate Color'),
            ),
          ],
        ),
      ),
    );
  }
}

We use an AnimationController to control the animation timing. The ColorTween smoothly changes the color from blue to red. We listen to the animation status to reverse direction when it reaches the end or start, creating a continuous loop. The AnimatedBuilder rebuilds the square container whenever the color changes. The button toggles the animation on and off, updating its label accordingly.

Final Result
Completed Screen
┌─────────────────────────────┐
│        Color Tween          │
│                             │
│          ■■■■■■■■           │
│          ■■■■■■■■           │
│          ■■■■■■■■           │
│                             │
│  [Animate Color]             │
└─────────────────────────────┘
Tap 'Animate Color' button: The square color smoothly changes from blue to red and back repeatedly.
Button label changes to 'Stop Animation' while animating.
Tap 'Stop Animation' button: The animation stops and the square color stays at current color.
Button label changes back to 'Animate Color'.
Stretch Goal
Add a slider to control the animation speed from 0.5 seconds to 5 seconds.
💡 Hint
Use the slider value to update the AnimationController's duration dynamically and restart the animation if running.