DartFlutter

Custom Animations with AnimationController & Tween

Custom Animations With AnimationController Tween

Introduction

Animations make Flutter apps feel smooth and responsive. When used well, they help users understand what is happening on screen. While Flutter provides many ready-made animated widgets, custom animations give you more control. By using AnimationController and Tween, you can fine-tune timing, curves, and behavior. In this guide, you will learn how these tools work together and how to build clean, performant animations from scratch.

Why Custom Animations Matter in Flutter

Animations are not only about visuals. More importantly, they help guide users through interactions and state changes. As a result, well-designed motion improves usability.

• Make transitions clearer
• Improve perceived performance
• Guide user attention naturally
• Add polish without clutter
• Create a more engaging experience

However, animations should stay subtle and purposeful.

Understanding AnimationController

At the center of every custom animation is the AnimationController. It produces values over time and controls how long an animation runs.

Creating an AnimationController

class MyWidgetState extends State<MyWidget>
    with SingleTickerProviderStateMixin {

  late AnimationController controller;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 300),
    );
  }

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

The vsync option is important because it prevents work when the widget is off screen. As a result, animations stay efficient.

What Is a Tween?

A Tween defines how values change from a start point to an end point. On its own, it does nothing. However, when combined with a controller, it becomes useful.

Basic Tween Example

final animation = Tween<double>(
  begin: 0.0,
  end: 1.0,
).animate(controller);

Here, the tween maps controller values into a range your UI can use.

Connecting Tween and AnimationController

Once connected, the animation can drive widget changes directly.

FadeTransition(
  opacity: animation,
  child: const Text("Hello Flutter"),
);

As the controller moves forward or backward, the widget updates smoothly.

Controlling the Animation Flow

Custom animations often need manual control. Fortunately, the API is simple.

controller.forward();
controller.reverse();

You can trigger these calls based on user actions, state changes, or lifecycle events.

Using Curves for Natural Motion

Straight-line animations feel stiff. Therefore, curves help motion feel more natural.

final curvedAnimation = CurvedAnimation(
  parent: controller,
  curve: Curves.easeInOut,
);

With curves, even simple animations feel smoother and more polished.

Common Animation Patterns

Most custom animations follow a few common patterns that work well in many apps.

Fade and Scale

ScaleTransition(
  scale: Tween(begin: 0.8, end: 1.0).animate(curvedAnimation),
  child: const Icon(Icons.star),
);

This pattern works well for dialogs and onboarding screens.

Slide Animations

SlideTransition(
  position: Tween(
    begin: const Offset(0, 0.2),
    end: Offset.zero,
  ).animate(curvedAnimation),
  child: const Text("Sliding In"),
);

Sliding motion helps users understand where content comes from.

Listening to Animation Status

Sometimes you need to react when an animation ends.

controller.addStatusListener((status) {
  if (status == AnimationStatus.completed) {
    // Animation finished
  }
});

This approach is useful for chaining animations or triggering logic.

Performance Best Practices

Smooth animations depend on good performance habits.

• Keep animations short and focused
• Avoid rebuilding large widget trees
• Use AnimatedBuilder for complex motion
• Dispose controllers properly
• Limit overlapping animations

By following these rules, your app avoids dropped frames.

When Custom Animations Are the Right Choice

Custom animations work best when you need:
• Full control over motion
• Coordinated transitions
• Brand-specific effects
• Gesture-driven feedback

For simpler cases, built-in animated widgets are often enough.

Common Mistakes to Avoid

Not Disposing Controllers

Forgetting to dispose controllers causes memory leaks.

Overusing Animations

Too much motion can confuse users instead of helping them.

Ignoring Accessibility

Always avoid excessive motion and respect system settings.

Avoiding these mistakes keeps animations helpful and user-friendly.

Conclusion

Custom animations with AnimationController and Tween give Flutter developers precise control over motion. By combining controllers, tweens, and curves, you can build smooth transitions that improve clarity and usability. If you want to create scalable UI systems, read Building Reusable UI Components in Flutter: Best Practices. For performance-focused guidance, see Flutter Performance Optimization Tips: Build Faster, Run Smoother. You can also explore the Flutter animation documentation and the AnimationController API reference. With the right balance, custom animations make Flutter apps feel polished and professional.

Leave a Comment