I want to create a custom timer widget in flutter. The timer should be at the center of the circle and the border of the circle should decrease as the timer decreases. Their should be a circular spot at the end of the border form where it is reducing. I want to apply gradient colors to the border of the circle.
I tried it using Circular progress indicator of flutter but I can't change the color of border to gradient and I can't put the spot at the reducing edge of the circle.
Please check this code snippet
import 'package:flutter/material.dart';
import 'dart:math';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Custom Timer Widget'),
),
body: const Center(
child: CustomTimerWidget(
duration: Duration(seconds: 10),
),
),
),
);
}
}
class CustomTimerWidget extends StatefulWidget {
final Duration duration;
const CustomTimerWidget({required this.duration});
@override
_CustomTimerWidgetState createState() => _CustomTimerWidgetState();
}
class _CustomTimerWidgetState extends State<CustomTimerWidget>
with TickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: widget.duration,
)..forward();
_animation = Tween<double>(begin: 0.0, end: 1.0).animate(_controller);
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Container(
width: 200,
height: 200,
child: CustomPaint(
painter: TimerPainter(progress: _animation.value),
child: Center(
child: Text(
'${(_animation.value * widget.duration.inSeconds).ceil()}s',
style: TextStyle(fontSize: 20.0, color: Colors.black),
),
),
),
);
},
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
class TimerPainter extends CustomPainter {
final double progress;
TimerPainter({required this.progress});
@override
void paint(Canvas canvas, Size size) {
final double strokeWidth = 10.0;
final double radius = (size.shortestSide - strokeWidth) / 2;
Paint outerCircle = Paint()
..strokeWidth = strokeWidth
..color = Colors.grey[300]!
..style = PaintingStyle.stroke;
Paint gradientCircle = Paint()
..strokeWidth = strokeWidth
..shader = LinearGradient(
colors: [Colors.blue, Colors.red],
).createShader(Rect.fromCircle(
center: Offset(size.width / 2, size.height / 2), radius: radius))
..style = PaintingStyle.stroke;
Paint spotPaint = Paint()
..color = Colors.black
..strokeWidth = 2.0
..style = PaintingStyle.fill;
canvas.drawCircle(
Offset(size.width / 2, size.height / 2), radius, outerCircle);
canvas.drawArc(
Rect.fromCircle(
center: Offset(size.width / 2, size.height / 2), radius: radius),
-pi / 2,
pi * 2 * progress,
false,
gradientCircle,
);
// Draw a circular spot at the end of the border
double spotX = size.width / 2 + radius * cos(pi * 2 * progress - pi / 2);
double spotY = size.height / 2 + radius * sin(pi * 2 * progress - pi / 2);
canvas.drawCircle(Offset(spotX, spotY), strokeWidth / 2, spotPaint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}