在计时器上进行的按钮周围的圆形进度指示器
Posted
技术标签:
【中文标题】在计时器上进行的按钮周围的圆形进度指示器【英文标题】:Circular Progress Indicator Around a Button that Progresses On a Timer 【发布时间】:2021-02-18 14:23:34 【问题描述】:我有一个播放按钮,可以播放用户录制的消息。一旦用户点击播放按钮,它就会变成一个停止按钮,显示一个圆形进度指示器,该指示器根据记录的消息总时间和当前曲目时间的百分比进行进度。
我做了一些工作,但还不够准确,具体取决于轨道的长度(4 秒对 6.5 秒),在循环进度指示器完成后轨道会运行更长时间,或者轨道会在之前结束进度指示器已完成。
我也希望进展顺利,而不是间歇性跳跃。
这里是停止按钮的代码,它采用double totalTime
,这是曲目播放的总时间,然后启动计时器和 AnimationController。
也是完全透明的,自定义画家是我在网上找到的,但并不完全理解它是如何工作的,所以即使没有问题,如果有人可以将其分解,我将不胜感激:D
import 'dart:async';
import 'dart:math';
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_icons/flutter_icons.dart';
class StopButton extends StatefulWidget
@override
_StopButtonState createState() => _StopButtonState();
final double totalTime;
final dynamic onClickFunction;
StopButton(this.totalTime, this.onClickFunction);
class _StopButtonState extends State<StopButton> with TickerProviderStateMixin
double percentage = 0.0;
double newPercentage = 0.0;
AnimationController percentageAnimationController;
Timer timer;
@override
void initState()
// TODO: implement initState
super.initState();
setState(()
percentage = 0.0;
);
percentageAnimationController =
AnimationController(vsync: this, duration: Duration(milliseconds: 1000))
..addListener(()
setState(()
percentage = lerpDouble(percentage, newPercentage,
percentageAnimationController.value);
);
);
startTime();
@override
void dispose()
// TODO: implement dispose
timer.cancel();
percentageAnimationController.dispose();
super.dispose();
void startTime()
setState(()
percentage = newPercentage;
newPercentage += 0.0;
if (newPercentage > widget.totalTime)
percentage = 0.0;
newPercentage = 0.0;
timer.cancel();
percentageAnimationController.forward(from: 0.0);
);
timer = Timer.periodic(Duration(seconds: 1), (timer)
print(timer.tick);
setState(()
percentage = newPercentage;
newPercentage += 1.0;
if (newPercentage > widget.totalTime)
percentage = 0.0;
newPercentage = 0.0;
timer.cancel();
percentageAnimationController.forward(from: 0.0);
);
);
@override
Widget build(BuildContext context)
return CustomPaint(
foregroundPainter: MyPainter(
lineColor: Colors.transparent,
completeColor: Color(0xFF133343),
completePercent: percentage,
width: 3.0,
totalTime: widget.totalTime,
),
child: Padding(
padding: EdgeInsets.all(0.0),
child: FloatingActionButton(
onPressed: () async
await widget.onClickFunction();
,
backgroundColor: Colors.white,
child: Icon(
MaterialCommunityIcons.stop,
color: Color(0xFF133343),
),
),
),
);
class MyPainter extends CustomPainter
Color lineColor;
Color completeColor;
double completePercent;
double width;
double totalTime;
MyPainter(
this.lineColor,
this.completeColor,
this.completePercent,
this.width,
this.totalTime);
@override
void paint(Canvas canvas, Size size)
Paint line = Paint()
..color = lineColor
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..strokeWidth = width;
Paint complete = Paint()
..color = completeColor
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..strokeWidth = width;
Offset center = Offset(size.width / 2, size.height / 2);
double radius = min(size.width / 2, size.height / 2);
canvas.drawCircle(center, radius, line);
double arcAngle = 2 * pi * (completePercent / totalTime);
canvas.drawArc(Rect.fromCircle(center: center, radius: radius), -pi / 2,
arcAngle, false, complete);
@override
bool shouldRepaint(CustomPainter oldDelegate)
return true;
【问题讨论】:
【参考方案1】:您已在下方添加自定义 CustomTimerPainter 以创建圆形指示器
class CustomTimerPainter extends CustomPainter
CustomTimerPainter(
this.animation,
this.backgroundColor,
this.color,
) : super(repaint: animation);
final Animation<double> animation;
final Color backgroundColor, color;
@override
void paint(Canvas canvas, Size size)
Paint paint = Paint()
..color = backgroundColor
..strokeWidth = 6.0
..strokeCap = StrokeCap.butt
..style = PaintingStyle.stroke;
canvas.drawCircle(size.center(Offset.zero), size.width / 2.0, paint);
paint.color = color;
double progress = (1.0 - animation.value) * 2 * math.pi;
canvas.drawArc(Offset.zero & size, math.pi * 1.5, progress, false, paint);
@override
bool shouldRepaint(CustomTimerPainter old)
return animation.value != old.animation.value ||
color != old.color ||
backgroundColor != old.backgroundColor;
添加指标后定义控制器
AnimationController controller;
@override
void initState()
super.initState();
controller = AnimationController(
vsync: this,
duration: Duration(seconds: 5),
);
最后一步是添加我们的自定义画家
floatingActionButton: Container(
height: 60,
width: 60,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white
),
child: GestureDetector(
child: CustomPaint(
painter: CustomTimerPainter(
animation: controller,
backgroundColor: Colors.white,
color: themeData.indicatorColor,
)),
onTap: ()
controller.reverse(
from: controller.value == 0.0
? 1.0
: controller.value);
,
),
),
【讨论】:
以上是关于在计时器上进行的按钮周围的圆形进度指示器的主要内容,如果未能解决你的问题,请参考以下文章