• Flutter:教你用CustomPaint画一个自定义的CircleProgressBar


    https://www.jianshu.com/p/2ea01ae02ffe

    Flutter:教你用CustomPaint画一个自定义的CircleProgressBar

    paint_page.dart

    import 'package:flutter/material.dart';
    import 'package:tetris/paint/paint.dart';
    
    
    class ProgressBarPage extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => ProgressBarState();
    }
    
    class ProgressBarState extends State<ProgressBarPage> {
      double progress = 0.0;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('CircleProgressBar'),
          ),
          body: Stack(
            alignment: Alignment.center,
            children: <Widget>[
              Text('Degree:${(progress * 360.0).round()}°',style: TextStyle(fontSize: 20.0),),
              CircleProgressBar(
                radius: 120.0,
                dotColor: Colors.pink,
                dotRadius: 18.0,
                shadowWidth: 2.0,
                progress: 0.0,
                progressChanged: (value) {
                  setState(() {
                    progress = value;
                  });
                },
              ),
            ],
          ),
        );
      }
    }
    

      

    paint.dart

    import 'dart:math';
    
    import 'package:flutter/material.dart';
    
    typedef ProgressChanged<double> = void Function(double value);
    
    num degToRad(num deg) => deg * (pi / 180.0);
    
    num radToDeg(num rad) => rad * (180.0 / pi);
    
    class CircleProgressBar extends StatefulWidget {
      final double radius;
      final double progress;
      final double dotRadius;
      final double shadowWidth;
      final Color shadowColor;
      final Color dotColor;
      final Color dotEdgeColor;
      final Color ringColor;
    
      final ProgressChanged progressChanged;
    
      const CircleProgressBar({
        Key key,
        @required this.radius,
        @required this.dotRadius,
        @required this.dotColor,
        this.shadowWidth = 2.0,
        this.shadowColor = Colors.black12,
        this.ringColor = const Color(0XFFF7F7FC),
        this.dotEdgeColor = const Color(0XFFF5F5FA),
        this.progress,
        this.progressChanged,
      }) : super(key: key);
    
      @override
      State<StatefulWidget> createState() => _CircleProgressState();
    }
    
    class _CircleProgressState extends State<CircleProgressBar>
        with SingleTickerProviderStateMixin {
      AnimationController progressController;
      bool isValidTouch = false;
      final GlobalKey paintKey = GlobalKey();
    
      @override
      void initState() {
        super.initState();
        progressController =
            AnimationController(duration: Duration(milliseconds: 300), vsync: this);
        if (widget.progress != null) progressController.value = widget.progress;
        progressController.addListener(() {
          if (widget.progressChanged != null)
            widget.progressChanged(progressController.value);
          setState(() {});
        });
      }
    
      @override
      void dispose() {
        progressController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        final double width = widget.radius * 2.0;
        final size = new Size(width, width);
        return GestureDetector(
          onPanStart: _onPanStart,
          onPanUpdate: _onPanUpdate,
          onPanEnd: _onPanEnd,
          child: Container(
            alignment: FractionalOffset.center,
            child: CustomPaint(
              key: paintKey,
              size: size,
              painter: ProgressPainter(
                  dotRadius: widget.dotRadius,
                  shadowWidth: widget.shadowWidth,
                  shadowColor: widget.shadowColor,
                  ringColor: widget.ringColor,
                  dotColor: widget.dotColor,
                  dotEdgeColor: widget.dotEdgeColor,
                  progress: progressController.value),
            ),
          ),
        );
      }
    
      void _onPanStart(DragStartDetails details) {
        RenderBox getBox = paintKey.currentContext.findRenderObject();
        Offset local = getBox.globalToLocal(details.globalPosition);
        isValidTouch = _checkValidTouch(local);
        if (!isValidTouch) {
          return;
        }
      }
    
      void _onPanUpdate(DragUpdateDetails details) {
        if (!isValidTouch) {
          return;
        }
        RenderBox getBox = paintKey.currentContext.findRenderObject();
        Offset local = getBox.globalToLocal(details.globalPosition);
        final double x = local.dx;
        final double y = local.dy;
        final double center = widget.radius;
        double radians = atan((x - center) / (center - y));
        if (y > center) {
          radians = radians + degToRad(180.0);
        } else if (x < center) {
          radians = radians + degToRad(360.0);
        }
        progressController.value = radians / degToRad(360.0);
      }
    
      void _onPanEnd(DragEndDetails details) {
        if (!isValidTouch) {
          return;
        }
      }
    
      bool _checkValidTouch(Offset pointer) {
        final double validInnerRadius = widget.radius - widget.dotRadius * 3;
        final double dx = pointer.dx;
        final double dy = pointer.dy;
        final double distanceToCenter =
        sqrt(pow(dx - widget.radius, 2) + pow(dy - widget.radius, 2));
        if (distanceToCenter < validInnerRadius ||
            distanceToCenter > widget.radius) {
          return false;
        }
        return true;
      }
    }
    
    class ProgressPainter extends CustomPainter {
      final double dotRadius;
      final double shadowWidth;
      final Color shadowColor;
      final Color dotColor;
      final Color dotEdgeColor;
      final Color ringColor;
      final double progress;
    
      ProgressPainter({
        this.dotRadius,
        this.shadowWidth = 2.0,
        this.shadowColor = Colors.black12,
        this.ringColor = const Color(0XFFF7F7FC),
        this.dotColor,
        this.dotEdgeColor = const Color(0XFFF5F5FA),
        this.progress,
      });
    
      @override
      void paint(Canvas canvas, Size size) {
        final double center = size.width * 0.5;
        final Offset offsetCenter = Offset(center, center);
        final double drawRadius = size.width * 0.5 - dotRadius;
        final angle = 360.0 * progress;
        final double radians = degToRad(angle);
    
        final double radiusOffset = dotRadius * 0.4;
        final double outerRadius = center - radiusOffset;
        final double innerRadius = center - dotRadius * 2 + radiusOffset;
    
        // draw shadow.
        final shadowPaint = Paint()
          ..style = PaintingStyle.stroke
          ..color = shadowColor
          ..strokeWidth = shadowWidth
          ..maskFilter = MaskFilter.blur(BlurStyle.normal, shadowWidth);
    //    canvas.drawCircle(offsetCenter, outerRadius, shadowPaint);
    //    canvas.drawCircle(offsetCenter, innerRadius, shadowPaint);
    
        Path path = Path.combine(PathOperation.difference, Path()..addOval(Rect.fromCircle(center: offsetCenter, radius: outerRadius)), Path()..addOval(Rect.fromCircle(center: offsetCenter, radius: innerRadius)));
        canvas.drawShadow(path, shadowColor, 4.0, true);
    
        // draw ring.
        final ringPaint = Paint()
          ..style = PaintingStyle.stroke
          ..color = ringColor
          ..strokeWidth = (outerRadius - innerRadius);
        canvas.drawCircle(offsetCenter, drawRadius, ringPaint);
    
        final Color currentDotColor = Color.alphaBlend(
            dotColor.withOpacity(0.7 + (0.3 * progress)), Colors.white);
    
        // draw progress.
        if (progress > 0.0) {
          final progressWidth = outerRadius - innerRadius + radiusOffset;
          final double offset = asin(progressWidth * 0.5 / drawRadius);
          if (radians > offset) {
            canvas.save();
            canvas.translate(0.0, size.width);
            canvas.rotate(degToRad(-90.0));
            final Gradient gradient = new SweepGradient(
              endAngle: radians,
              colors: [
                Colors.white,
                currentDotColor,
              ],
            );
            final Rect arcRect =
            Rect.fromCircle(center: offsetCenter, radius: drawRadius);
            final progressPaint = Paint()
              ..style = PaintingStyle.stroke
              ..strokeCap = StrokeCap.round
              ..strokeWidth = progressWidth
              ..shader = gradient.createShader(arcRect);
            canvas.drawArc(
                arcRect, offset, radians - offset, false, progressPaint);
            canvas.restore();
          }
        }
    
        // draw dot.
        final double dx = center + drawRadius * sin(radians);
        final double dy = center - drawRadius * cos(radians);
        final dotPaint = Paint()..color = currentDotColor;
        canvas.drawCircle(new Offset(dx, dy), dotRadius, dotPaint);
        dotPaint
          ..color = dotEdgeColor
          ..style = PaintingStyle.stroke
          ..strokeWidth = dotRadius * 0.3;
        canvas.drawCircle(new Offset(dx, dy), dotRadius, dotPaint);
    
    //    canvas.drawLine(
    //        Offset(center, 0.0),
    //        Offset(center, size.height),
    //        Paint()
    //          ..strokeWidth = 1.0
    //          ..color = Colors.black);  // 测试基准线
      }
    
      @override
      bool shouldRepaint(CustomPainter oldDelegate) {
        return true;
      }
    }
    

      

  • 相关阅读:
    multidownloadXkcd 多线程抓图
    51job_selenium测试2
    51job_selenium测试
    python爬虫 前程无忧网页抓取
    化工pdf下载
    Velocity写法注意
    Velocity中文乱码问题解决方法
    velcoity使用说明:foreach指令
    strults2标签s:set的用法
    struts提交action乱码
  • 原文地址:https://www.cnblogs.com/pythonClub/p/10859169.html
Copyright © 2020-2023  润新知