Flutter Custom Paint: Interactive UI Elements Examples
28 June
Flutter is a versatile framework that empowers developers to build beautiful and intuitive user interfaces. While Flutter provides a wide range of pre-built widgets, sometimes you may need to create custom UI elements that offer a unique user experience. In such cases, Flutter’s CustomPaint widget comes to the rescue.
In this article, we will explore Flutter’s CustomPaint widget and learn how to create interactive and custom UI elements with it. We will cover everything you need to know to get started with CustomPaint and demonstrate how to leverage its power to craft captivating UI elements.
Understanding CustomPaint
At its core, CustomPaint is a powerful widget that allows you to paint custom graphics on the screen by overriding its paint method. With this flexibility, you can draw anything you want on the screen, from simple shapes to intricate illustrations.
To demonstrate the capabilities of CustomPaint, let’s create a custom UI element – a circular progress indicator. This indicator will have its own unique styling and interactivity.
class CustomProgressIndicator extends StatefulWidget { @override _CustomProgressIndicatorState createState() => _CustomProgressIndicatorState(); } class _CustomProgressIndicatorState extends State<CustomProgressIndicator> with SingleTickerProviderStateMixin { AnimationController _animationController; double _progress = 0.0; @override void initState() { super.initState(); _animationController = AnimationController( duration: const Duration(seconds: 2), vsync: this, )..addListener(() { setState(() { _progress = (_animationController.value * 100); }); }); _animationController.repeat(reverse: true); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return CustomPaint( painter: CustomProgressPainter(progress: _progress), size: Size(100, 100), ); } } class CustomProgressPainter extends CustomPainter { final double progress; CustomProgressPainter({required this.progress}); @override void paint(Canvas canvas, Size size) { final center = Offset(size.width / 2, size.height / 2); final radius = size.width / 2; final strokeWidth = 10.0; final paint = Paint() ..color = Colors.blue ..style = PaintingStyle.stroke ..strokeWidth = strokeWidth; canvas.drawCircle(center, radius - (strokeWidth / 2), paint); final progressPaint = Paint() ..color = Colors.blue ..style = PaintingStyle.stroke ..strokeCap = StrokeCap.round ..strokeWidth = strokeWidth; final sweepAngle = 2 * pi * (progress / 100); canvas.drawArc( Rect.fromCircle(center: center, radius: radius - (strokeWidth / 2)), -pi / 2, sweepAngle, false, progressPaint, ); } @override bool shouldRepaint(CustomProgressPainter oldDelegate) { return progress != oldDelegate.progress; } }
In the example above, we have a CustomProgressIndicator widget that extends StatefulWidget. It uses an AnimationController to animate the progress of the indicator. The CustomProgressPainter class is responsible for drawing the circular progress indicator on the screen.
To animate the progress, we override the addListener method of the AnimationController and update the _progress state variable. By calling setState, we ensure that the UI is rebuilt and shows the updated progress.
The CustomProgressPainter paints the circular progress indicator using the paint method. We use the Canvas object to draw a circle and an arc representing the progress. The shouldRepaint method is implemented to optimize performance by only repainting the indicator when the progress changes.
Integrating Gestures and Animation
One of the exciting aspects of creating custom UI elements with CustomPaint is the ability to integrate gestures and animation. By combining CustomPaint with Flutter’s GestureDetector and AnimationController, you can add interactivity and smooth animations to your custom elements.
Let’s improve our custom progress indicator by allowing users to tap on it to pause and resume the animation.
class _CustomProgressIndicatorState extends State<CustomProgressIndicator> with SingleTickerProviderStateMixin { AnimationController _animationController; double _progress = 0.0; bool _isPaused = false; @override void initState() { super.initState(); _animationController = AnimationController( duration: const Duration(seconds: 2), vsync: this, )..addListener(() { setState(() { _progress = (_animationController.value * 100); }); }); _animationController.repeat(reverse: true); } @override void dispose() { _animationController.dispose(); super.dispose(); } void _toggleAnimation() { setState(() { _isPaused = !_isPaused; if (_isPaused) { _animationController.stop(); } else { _animationController.repeat(reverse: true); } }); } @override Widget build(BuildContext context) { return GestureDetector( onTap: _toggleAnimation, child: CustomPaint( painter: CustomProgressPainter(progress: _progress), size: Size(100, 100), ), ); } }
In the modified example above, we have added a _toggleAnimation method that is triggered when the progress indicator is tapped. This method toggles the animation on and off by stopping or repeating the animation controller. The GestureDetector widget wraps the CustomPaint widget, allowing users to interact with the progress indicator by tapping on it.
Conclusion
Flutter’s CustomPaint widget enables developers to create interactive and custom UI elements that suit the specific needs of their applications. By leveraging the power of CustomPaint, you can craft captivating and unique user experiences that set your app apart.
In this article, we explored the fundamentals of CustomPaint and demonstrated how to create interactive UI elements with a custom progress indicator as an example. We also discussed how to integrate gestures and animation to enhance your custom elements’ interactivity and visual appeal.
With the knowledge gained from this article, you now have the foundation to dive into the world of CustomPaint and create stunning, interactive, and custom UI elements that will delight your users and elevate your Flutter app to the next level.