|
import 'dart:math' as math; |
|
|
|
import 'package:flutter/material.dart'; |
|
|
|
class SkipCircleButton extends StatefulWidget { |
|
final String title; |
|
final VoidCallback onTap; |
|
|
|
final Duration duration; |
|
final double size; |
|
|
|
const SkipCircleButton({ |
|
Key key, |
|
@required this.onTap, |
|
this.title = "跳过", |
|
this.size = 44.0, |
|
this.duration = const Duration(seconds: 5), |
|
}) : super(key: key); |
|
|
|
@override |
|
_SkipCircleButtonState createState() => _SkipCircleButtonState(); |
|
} |
|
|
|
class _SkipCircleButtonState extends State<SkipCircleButton> |
|
with SingleTickerProviderStateMixin { |
|
AnimationController controller; |
|
|
|
@override |
|
void initState() { |
|
super.initState(); |
|
controller = AnimationController(vsync: this, duration: widget.duration); |
|
controller.addStatusListener(_onStatusCallback); |
|
controller.animateTo(1.0); |
|
} |
|
|
|
@override |
|
void dispose() { |
|
controller.dispose(); |
|
controller.removeStatusListener(_onStatusCallback); |
|
super.dispose(); |
|
} |
|
|
|
void _onStatusCallback(AnimationStatus status) { |
|
if (status == AnimationStatus.completed) { |
|
widget.onTap(); |
|
} |
|
} |
|
|
|
@override |
|
Widget build(BuildContext context) { |
|
return AnimatedBuilder( |
|
animation: controller, |
|
builder: (BuildContext context, Widget child) { |
|
return CustomPaint( |
|
child: InkWell( |
|
onTap: widget.onTap, |
|
child: Container( |
|
width: widget.size, |
|
height: widget.size, |
|
), |
|
), |
|
painter: _CountDownCirclePainter( |
|
widget.title, |
|
controller.value, |
|
), |
|
); |
|
}, |
|
); |
|
} |
|
} |
|
|
|
class _CountDownCirclePainter extends CustomPainter { |
|
String title; |
|
double progress; |
|
|
|
TextPainter textPainter; |
|
|
|
Color backgroundColor = Colors.white.withOpacity(0.3); |
|
Paint backgroundPaint; |
|
|
|
Color progressColor = C.themeGreen; |
|
Paint progressPaint; |
|
|
|
_CountDownCirclePainter(this.title, this.progress) { |
|
textPainter = TextPainter( |
|
textDirection: TextDirection.ltr, |
|
text: TextSpan( |
|
text: title, |
|
style: TextStyle( |
|
fontSize: 14.0, |
|
color: Colors.white, |
|
), |
|
), |
|
); |
|
|
|
backgroundPaint = Paint(); |
|
|
|
backgroundPaint..color = backgroundColor; |
|
|
|
progressPaint = Paint() |
|
..color = progressColor |
|
..style = PaintingStyle.stroke |
|
..strokeWidth = 1.0; |
|
} |
|
|
|
@override |
|
void paint(Canvas canvas, Size size) { |
|
textPainter.layout(maxWidth: size.width); |
|
|
|
var center = Offset.zero.translate(size.width / 2, size.height / 2); |
|
canvas.drawCircle( |
|
center, |
|
size.width / 2 - 1, |
|
backgroundPaint, |
|
); |
|
|
|
canvas.drawArc( |
|
Rect.fromPoints(Offset(0.0, 0.0), Offset(size.width, size.height)), |
|
0.0, |
|
math.pi / 180 * 360 * progress, |
|
false, |
|
progressPaint, |
|
); |
|
|
|
textPainter.paint( |
|
canvas, |
|
center.translate(-textPainter.width / 2, -textPainter.height / 2), |
|
); |
|
} |
|
|
|
@override |
|
bool shouldRepaint(CustomPainter oldDelegate) => true; |
|
} |