1

我有一个播放按钮,可以播放用户录制的消息。一旦用户点击播放按钮,它就会变成一个停止按钮,显示一个圆形进度指示器,该指示器根据记录的消息总时间和当前轨道时间的百分比进行进度。

我做了一些工作,但还不够准确,具体取决于轨道的长度(4 秒对 6.5 秒),在循环进度指示器完成后轨道将运行更长的时间,或者轨道将在进度指示器之前结束已经完成了。

我也希望进展顺利,而不是间隔跳跃。 在此处输入图像描述

这是停止按钮的代码,它采用 adouble 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;
  }
}
4

1 回答 1

4

您已在自定义 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);
      },
    ),
  ),
于 2021-05-26T12:09:29.143 回答