【Flutter】画布使用

3,229 阅读3分钟

自定义样式

最近Flutter项目新需求中需要实现圆弧样式,如下图所示:

在Flutter自身UI组件中好像也没有直接可用圆弧并带缺口的组件。所以圆弧样式就需要自己自定义绘制实现。 在Flutter中同样也有画布组件供开发者绘制自定义样式。

画布

画布组件CustomPaint,绘制内容通过painter和foregroundPainter。painter绘制在child之前,foregroundPainter绘制在child之后,因此child内容覆盖在painter上层,foregroundPainter内容覆盖在child上层。

CustomPaint(
  painter: CanvasPainter(),
  foregroundPainter: ForegroundPainter(),
  child: Container(
      height: 50,
      decoration: BoxDecoration(
        border: Border.all(color: Colors.black, width: 5),
      ),
      child: Text("我是CustomPaint的child"),
  ),
),

绘制

绘制部分的实现由CustomPainter完成。首先创建一个继承CustomPainter的类对象。

  • paint方法绘制通过canvas内容,size获取canvas大小。
  • shouldRepaint判断是否需要重绘。
class DemoPainter extends CustomPainter{
  @override
  void paint(Canvas canvas, Size size) {
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return null;
  }
}

圆弧计算

首先了解1度 = pi / 180,起始度数 = 度数 * pi / 180。

drawArc方法角度0度位置是距离圆点水平位置右侧,而度数增加的正方向是顺时针方向。我们圆弧绘制的第一个起始度数参数是-240度(-240 * (pi / 180)),具体位置如下图所示。然后已知0度位置并知道360度位置,360度当然是和0度重合的😂。-240度位置距离圆点垂直位置下方度数为30,所以缺口总共度数为60,左右对齐各30度角。因此缺口的度数为60度,圆弧划过的总共度数为300度,最后得出第二个度数参数为 300 * (pi / 180)。

圆弧实现

绘制圆弧使用drawArc方法,设置绘制圆形尺寸(圆心,半径)、起始角度、圆弧角度、是否闭合。

  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = Paint();
    paint.style = PaintingStyle.stroke;
    paint.strokeWidth = 5;
    paint.strokeCap = StrokeCap.round;
    paint.color = Colors.white;
    canvas.drawArc(
        Rect.fromCircle(
            center: Offset(size.width / 2, size.height / 2), radius: 70),
        -240 * (pi / 180),
        300 * (pi / 180),
        false,
        paint);
    paint.strokeWidth = 2;
    canvas.drawArc(
        Rect.fromCircle(
            center: Offset(size.width / 2, size.height / 2), radius: 65),
        -240 * (pi / 180),
        300 * (pi / 180),
        false,
        paint);
    paint.strokeWidth = 1;
    canvas.drawArc(
        Rect.fromCircle(
            center: Offset(size.width / 2, size.height / 2), radius: 60),
        -240 * (pi / 180),
        300 * (pi / 180),
        false,
        paint);
  }

另外CustomPainter还有child,可以通过Stack将文本内容通过Text居中显示,如果有条件UI中间文本和按钮当然可以通过画布绘制的方式实现,圆弧绘制的完整画布代码如下:

 DemoPainter(
   painter: CanvasPainter(),
   foregroundPainter: ForegroundPainter(),
   child: Container(
     height: 50,
     decoration: BoxDecoration(
       border: Border.all(color: Colors.black, width: 5),
     ),
     child: Stack(
       children: <Widget>[
         Text("我是CustomPaint的child"),
         Center(
           child: Text(
             "96",
             style: TextStyle(
               color: Colors.white,
               fontSize: 30,
               fontWeight: FontWeight.bold,
             ),
           ),
         )
       ],
     ),
   ),
 ),

最终效果

这只是简单的画布实现自定义样式功能,我们还可以用画布绘制图片、根据数学公式绘制更多图形、文字和其他绚丽自定义样式。Canvas不管是在前端、客户端都是会有类似的使用场景,而且接触多了之后会发现每个语言上封装的接口和方法都很相似,因为在做Android开发的时候接触过确实是大同小异,所以画布其他具体功能不再展开细说。

最后的最后介绍两个优秀的Flutter图表开源库Syncfusion Flutter ChartsFlutter Charting 。你会惊喜的发现通过画布实现图表功能原来可以这么酷炫。

🚀完整代码看这里🚀

参考