当前位置 : 主页 > 手机开发 > android >

基于Flutter实现多边形和多角星组件

来源:互联网 收集:自由互联 发布时间:2023-02-01
目录 前言 组件功能 1、原理 2、找点 小结: 前言 开发中,免不了会用到多边形、多角星等图案,比较常用的多边形比如雷达图、多角星比如评价星级的五角星等,本篇文章就使用Flu
目录
  • 前言
    • 组件功能
  • 1、原理
    • 2、找点
      • 小结:

        前言

        开发中,免不了会用到多边形、多角星等图案,比较常用的多边形比如雷达图、多角星比如评价星级的五角星等,本篇文章就使用Flutter绘制封装一个这样的组件。

        组件功能

        • 正多边形
        • 正多角星
        • 支持同时绘制多边形和多角星
        • 角的饱满度调整

        1、原理

        五角星为例:

        可以看到,在一个五角星中,一共有10个点,有5个点平均分布在大圆上面,有5个点平均分布在小圆上面,相当于对360度进行了10等分,那么我们只需要将这10个点找到,用线连起来即可。

        2、找点

        既然知道了点的分布规律,我们只需要拿到圆的半径通过三角函数就能得到每个点的坐标,通过path路径进行连接即可。

        // 大圆半径
        double r = bigR ?? size.width / 2 / 2;
        // 小圆半径
        double r2 = smallR ?? size.width / 2 / 2 - 12;
        
        Path path = Path();
        // 设置起点
        path.moveTo(r * cos(pi / count), r * sin(pi / count));
        // 将圆等分 count = 角的个数
        /// 绘制角
          for (int i = 2; i <= count * 2; i++) {
            if (i.isEven) {
              path.lineTo(r2 * cos(pi / count * i), r2 * sin(pi / count * i));
            } else {
              path.lineTo(r * cos(pi / count * i), r * sin(pi / count * i));
            }
          }
          // 闭合
          path.close();
          canvas.drawPath(path, paint2);
        
        // 绘制辅助线
        path.reset();
        for (int i = 1; i <= count * 2; i++) {
          if (i.isEven) {
            path.reset();
            path.lineTo(r2 * cos(pi / count * i), r2 * sin(pi / count * i));
            canvas.drawPath(path, paint2..color = Colors.redAccent);
          } else {
            path.reset();
            path.lineTo(r * cos(pi / count * i), r * sin(pi / count * i));
            canvas.drawPath(path, paint2..color = Colors.blue);
          }
        }

        默认效果是这样的,

        画布默认0度是X轴右移方向,如果需要将一个角朝着正上,这里需要将画布进行旋转一定角度,将0度改为Y轴向上方面,然后再偏移一定角度即可。

        //旋转角度让尖角朝上
        canvas.rotate(pi / 2 * 3 + pi / count);

        角的点找到了,那么多边形就直接连接大圆上的角就行了,就很简单。

        角的饱满度通过修改小圆半径即可。

        最终效果图:

        源码:

        enum Type {
          angle, // 角
          side, // 边
          all, // 都有
        }
        
        /// 角 边 型
        class Polygonal extends StatelessWidget {
          final double size; // 组件大小
          final double? bigR; // 大圆半径
          final double? smallR; // 小圆半径
          final int count; // 几边形
          final Type type; // 五角星or五边形
          final bool isFill; // 是否填充
          final Color color; // 颜色
        
          const Polygonal(
              {Key? key,
              this.size = 80,
              this.bigR,
              this.smallR,
              this.count = 3,
              this.type = Type.angle,
              this.isFill = false,
              this.color = Colors.black87})
              : super(key: key);
        
          @override
          Widget build(BuildContext context) {
            return CustomPaint(
              size: Size(size, size),
              painter: _PolygonalPainter(bigR, smallR,
                  color: color, count: count, type: type, isFill: isFill),
            );
          }
        }
        
        class _PolygonalPainter extends CustomPainter {
          final double? bigR;
          final double? smallR;
          final int count; // 几边形
          final Type type; // 五角星or五边形
          final bool isFill; // 是否填充
          final Color color; // 颜色
          _PolygonalPainter(this.bigR, this.smallR,
              {required this.count,
              required this.type,
              required this.isFill,
              required this.color});
        
          @override
          void paint(Canvas canvas, Size size) {
            canvas.clipRect(Offset.zero & size);
            canvas.translate(size.width / 2, size.height / 2);
            Paint paint2 = Paint()
              ..color = color
              ..strokeJoin = StrokeJoin.round
              ..style = isFill ? PaintingStyle.fill : PaintingStyle.stroke
              ..strokeWidth = 2;
            double r = bigR ?? size.width / 2 / 2;
            double r2 = smallR ?? size.width / 2 / 2 - 12;
            // 将圆等分
            Path path = Path();
            canvas.rotate(pi / count + pi / 2 * 3);
            path.moveTo(r * cos(pi / count), r * sin(pi / count));
        
            /// 绘制角
            if (type == Type.angle || type == Type.all) {
              for (int i = 2; i <= count * 2; i++) {
                if (i.isEven) {
                  path.lineTo(r2 * cos(pi / count * i), r2 * sin(pi / count * i));
                } else {
                  path.lineTo(r * cos(pi / count * i), r * sin(pi / count * i));
                }
              }
              path.close();
              canvas.drawPath(path, paint2);
            }
        
            /// 绘制边
            if (type == Type.side || type == Type.all) {
              path.reset();
              path.moveTo(r * cos(pi / count), r * sin(pi / count));
              for (int i = 2; i <= count * 2; i++) {
                if (i.isOdd) {
                  path.lineTo(r * cos(pi / count * i), r * sin(pi / count * i));
                }
              }
              path.close();
              canvas.drawPath(path, paint2);
            }
        
          }
        
          @override
          bool shouldRepaint(covariant CustomPainter oldDelegate) {
            return false;
          }
        }

        小结:

        圆其实可以理解为一个无限边的正多边形,这也印证了世上没有完美的圆。因为边是无限的,通过本篇我们利用圆的辅助绘制了多边形以及多角星,希望对大家有所帮助 ~

        以上就是基于Flutter实现多边形和多角星组件的详细内容,更多关于Flutter多边形组件的资料请关注自由互联其它相关文章!

        网友评论