Custom widgets encapsulate reusable UI. Flutter’s animation system supports implicit (AnimatedContainer) and explicit (AnimationController) animations.

Custom Widget

  class RatingBar extends StatelessWidget {
  final int rating;
  final int maxRating;
  const RatingBar({super.key, required this.rating, this.maxRating = 5});

  @override
  Widget build(BuildContext context) {
    return Row(
      children: List.generate(maxRating, (i) =>
        Icon(i < rating ? Icons.star : Icons.star_border)),
    );
  }
}
  

Implicit Animation

  AnimatedContainer(
  duration: Duration(milliseconds: 300),
  width: expanded ? 200 : 100,
  height: 100,
  color: expanded ? Colors.blue : Colors.red,
)
  

Explicit Animation

  class _State extends State<MyWidget> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: Duration(seconds: 1));
    _animation = Tween<double>(begin: 0, end: 1).animate(_controller);
    _controller.forward();
  }

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

Hero Animation

  Hero(
  tag: 'avatar-$id',
  child: CircleAvatar(backgroundImage: NetworkImage(url)),
)
  

Custom Painter

  class MyPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()..color = Colors.blue;
    canvas.drawCircle(Offset(size.width/2, size.height/2), 50, paint);
  }
  @override
  bool shouldRepaint(covariant CustomPainter old) => false;
}
  

Common Pitfalls

  • Ignoring null safety warnings and using ! operator carelessly.
  • Calling setState excessively causing unnecessary rebuilds.
  • Mixing async patterns without proper error handling.
  • Hardcoding values that should be theme constants.

Best Practices

  • Prefer const constructors for static widgets.
  • Use named parameters for widget constructors.
  • Extract reusable widgets into separate files.
  • Write widget tests for critical UI paths.

Memory and Performance Notes

Animations run at 60/120fps on GPU layer. Avoid rebuilding during animation.

Exercise

Create an animated expand/collapse card using AnimatedCrossFade or explicit AnimationController.

Hint: Always dispose AnimationController in dispose().

Summary

Practice with Flutter DevTools open to observe rebuilds and performance.

Debugging Checklist

  1. Read the full error in the console.
  2. Use Flutter DevTools widget inspector.
  3. Hot restart vs hot reload — know the difference.
  4. Check null safety and type errors first.
  5. Simplify widget tree to isolate the issue.

Real-World Application

Production Flutter apps combine these patterns with analytics, crash reporting, and CI/CD.

Further Reading

Flutter documentation, Dart language tour, and pub.dev packages.

Additional Examples

Consider how this topic applies in a larger project:

  // Break the problem into smaller functions
// Test each function independently
// Integrate incrementally
  

Working through variations of the examples above builds deeper understanding than reading alone.