Custom Widgets and Animations
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
- Read the full error in the console.
- Use Flutter DevTools widget inspector.
- Hot restart vs hot reload — know the difference.
- Check null safety and type errors first.
- 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.