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

2022-05-26 08:49:15
目录
前言组件功能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多边形组件的资料请关注易采站长站其它相关文章!