【问题标题】:Flutter Draw a circle border with 3 multiple colors and valuesFlutter 用 3 种多种颜色和值绘制圆形边框
【发布时间】:2021-04-07 21:03:11
【问题描述】:

如何绘制具有多个值的图表样式圆形边框?还动画圆中的每个值动态扩展填充 100% 的圆?

【问题讨论】:

    标签: flutter geometry border draw


    【解决方案1】:

    动画可以由 TweenAnimationBuilder 处理,它会在构建时播放。 为了达到预期的效果,我们必须使用 customPainter。

    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    import 'dart:math' as math;
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: MyHomePage(),
          debugShowCheckedModeBanner: false,
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: TweenAnimationBuilder(
              duration: const Duration(seconds: 2),
              tween: Tween(begin: 0.0, end: 1.0),
              curve: Curves.easeOutCubic,
              builder: (BuildContext context, dynamic value, Widget child) {
                return CustomPaint(
                  painter: OpenPainter(
                      totalQuestions: 300,
                      learned: 75,
                      notLearned: 75,
                      range: value),
                );
              },
            ),
          ),
        );
      }
    }
    
    class OpenPainter extends CustomPainter {
      final learned;
      final notLearned;
      final range;
      final totalQuestions;
      double pi = math.pi;
    
      OpenPainter({this.learned, this.totalQuestions, this.notLearned, this.range});
      @override
      void paint(Canvas canvas, Size size) {
        double strokeWidth = 7;
        Rect myRect = const Offset(-50.0, -50.0) & const Size(100.0, 100.0);
        
        var paint1 = Paint()
          ..color = Colors.red
          ..strokeWidth = strokeWidth
          ..style = PaintingStyle.stroke;
        var paint2 = Paint()
          ..color = Colors.green
          ..strokeWidth = strokeWidth
          ..style = PaintingStyle.stroke;
        var paint3 = Paint()
          ..color = Colors.yellow
          ..strokeWidth = strokeWidth
          ..style = PaintingStyle.stroke;
    
        double firstLineRadianStart = 0;
        double _unAnswered = (totalQuestions - notLearned - learned) * range / totalQuestions;
        double firstLineRadianEnd = (360 * _unAnswered) * math.pi / 180;
        canvas.drawArc(
            myRect, firstLineRadianStart, firstLineRadianEnd, false, paint1);
    
        double _learned = (learned) * range / totalQuestions;
        double secondLineRadianEnd = getRadians(_learned);
        canvas.drawArc(myRect, firstLineRadianEnd, secondLineRadianEnd, false, paint2);
        double _notLearned = (notLearned) * range / totalQuestions;
        double thirdLineRadianEnd = getRadians(_notLearned);
        canvas.drawArc(myRect, firstLineRadianEnd + secondLineRadianEnd, thirdLineRadianEnd, false, paint3);
    
        // drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint)
      }
    
      double getRadians(double value) {
        return (360 * value) * pi / 180;
      }
    
      @override
      bool shouldRepaint(CustomPainter oldDelegate) => true;
    }
    
    

    希望有人会觉得这很有帮助:)随时改进!快乐编码!

    【讨论】:

    • 您应该创建另一个带有详细问题的线程。如果我理解正确,您可以通过构造函数传入偏移参数。不确定“动态”部分。或者使用 MediaQuery.of(context).size.width 来缩放屏幕宽度。
    • @ArslanKaleem 使用某种animationController 并对其进行操作,例如animationController.forward() 按钮单击或类似的东西:) 或者最坏的情况是将此动画创建为分离的有状态小部件并使用setstate 重建整个小部件
    【解决方案2】:

    感谢 Paulius Greičiūnas 的回答,我实现了一种更通用的方法来绘制不同颜色的圆圈。您只需将颜色的出现指定为地图和圆的大小。

    class MultipleColorCircle extends StatelessWidget {
      final Map<Color, int> colorOccurrences;
      final double height;
      final Widget? child;
      @override
      MultipleColorCircle(
          {required this.colorOccurrences, this.height = 20, this.child});
      Widget build(BuildContext context) => Container(
            height: height,
            width: height,
            child: CustomPaint(
                size: Size(20, 20),
                child: Center(child: child),
                painter: _MultipleColorCirclePainter(
                  colorOccurrences: colorOccurrences,
                  height: height,
                )),
          );
    }
    
    class _MultipleColorCirclePainter extends CustomPainter {
      final Map<Color, int> colorOccurrences;
      final double height;
      @override
      _MultipleColorCirclePainter(
          {required this.colorOccurrences, required this.height});
      double pi = math.pi;
    
      @override
      void paint(Canvas canvas, Size size) {
        double strokeWidth = 1;
        Rect myRect =
            Rect.fromCircle(center: Offset(height / 2, height / 2), radius: height);
    
        double radianStart = 0;
        double radianLength = 0;
        int allOccurrences = 0;
        //set denominator
        colorOccurrences.forEach((color, occurrence) {
          allOccurrences += occurrence;
        });
        colorOccurrences.forEach((color, occurrence) {
          double percent = occurrence / allOccurrences;
          radianLength = 2 * percent * math.pi;
          canvas.drawArc(
              myRect,
              radianStart,
              radianLength,
              false,
              Paint()
                ..color = color
                ..strokeWidth = strokeWidth
                ..style = PaintingStyle.stroke);
          radianStart += radianLength;
        });
      }
    
      @override
      bool shouldRepaint(CustomPainter oldDelegate) => true;
    }
    

    使用地图,例如{Colors.blue: 2, Colors.green: 1} 你会得到一个 1/3 绿色和 2/3 蓝色的圆圈。 请注意,您还可以定义一个孩子,以便圆圈中包含内容。这是我在日历中使用的一个示例,其中包含多个包含内容的圆圈。

    【讨论】:

    • 感谢分享! :) 你应该为每一个添加动画:D
    • 你能在这个圆圈中间画Assetimage吗?
    • 当然,参数 child 是 Widget? 类型。所以你可以在其中传递你的 AssetImage('my image.png') 。您可以设置图像的大小以确保它适合。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-07
    相关资源
    最近更新 更多