
                            
                            因收到Google相关通知，网站将会择期关闭。相关通知内容
                            
                            
                            19 认识自定义绘制组件
                            1.从绘制点开始说起

我们先通过绘制点来了解一下 Flutter 中绘制的使用方式。左图中是新建的 Paper 组件作为白板主界面；右图在白板的指定坐标处绘制了四个方形的点：




空白
绘制四个点










Paper 组件如下，由于之后需要进行切换画笔颜色、粗细的操作；涉及到界面中状态的变化，所以这里继承自 StatefulWidget，在状态类的 build 方法中，完成界面的构建逻辑。 PaperAppBar 是单独封装的头部标题组件，和之前类似，就不赘述了；现在主要是想让 body 处设置为可绘制的组件。

class Paper extends StatefulWidget {
  const Paper({Key? key}) : super(key: key);

  @override
  State<Paper> createState() => _PaperState();
}

class _PaperState extends State<Paper> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: PaperAppBar(onClear: _clear,),
      body: //TODO
    );
  }

  void _clear() {}
}




我们已经知道， Flutter 中的所有界面呈现，都和 Widget 息息相关，绘制也不例外。在 Flutter 中接触到 Canvas 最常用的方式是 CustomPaint 组件 + CustomPainter 画板组合。下面代码，将 body 设置为 CustomPaint 组件；CustomPaint 在构造时传入 painter 参数是 CustomPainter 的子类。

自定义绘制，就是指继承 CustomPainter 完成绘制逻辑，比如这里的 PaperPainter 画板。另外，我们希望画布的尺寸填充剩余空间，可以将 child 指定为 ConstrainedBox ，并通过 BoxConstraints.expand() 的约束。

body: CustomPaint(
  painter: PaperPainter(),
  child: ConstrainedBox(constraints: const BoxConstraints.expand()),
),


也就是说，对于自定义绘制来说，最重要的是 CustomPainter 子类代码的实现，这里通过 PaperPainter 来完成绘制逻辑。在 paint 回调中，可以访问到 Canvas 对象和画板的尺寸 Size 。
在该方法中通过调用 Canvas 的相关方法就可以进行绘制。比如这里使用 drawPoints 绘制点集，其中需要传入三个参数，分别是:


点的模式 PointMode : 共三种模式， points、lines、polygon
点集 List<Offset> ： 点的坐标列表
画笔 Paint : 绘制时的配置参数


class PaperPainter extends CustomPainter{

  @override
  void paint(Canvas canvas, Size size) {
    List<Offset> points = const [
      Offset(100,100),
      Offset(100,150),
      Offset(150,150),
      Offset(200,100),
    ];

    Paint paint = Paint();
    paint.strokeWidth = 10;
    canvas.drawPoints(PointMode.points, points , paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;

}


上面点模式是 PointMode.points ，也就是绘制一个个点。如下是另外两者模式的效果，看起来也很清晰：PointMode.lines 会将点集分为若干对，没对连接成线；PointMode.polygon 会将点依次连接；




PointMode.lines
PointMode.polygon










到这里，就通过 Canvas 完成了一个最基础的点集绘制案例，当前代码位置 paper.dart 。接下来，介绍一下 Paint 对象，看看你的画笔有哪些功能。



2. 简单认识画笔的属性

可以先回想一下，我们现实中画画时用的笔有哪些特性：很自然的可以想到: 颜色、粗细 。 这两个配置项分别对应 strokeWidth 和 color 属性，在绘制之前通过直接 paint 对象设置即可：

Paint paint = Paint();
paint.strokeWidth = 10;
paint.color = Colors.red;





粗细 strokeWidth
颜色 color













之前线间的连接很突兀，可以使用将 strokeCap 设置为 StrokeCap.round 让线编程圆头：

paint.strokeCap = StrokeCap.round;





StrokeCap.butt
StrokeCap.round










这里面向新手，对于绘制的知识也点到为止，能满足当前需求即可，不会进行非常系统的介绍。不过感兴趣的可以看我的 《Flutter 绘制指南 - 妙笔生花》 小册，其中对于绘制方方面面都介绍的比较详细。



3. 简单的基础图形绘制

Canvas 中提供了一些基础图形的绘制，比如 圆形、矩形、圆角矩形、椭圆、圆弧 等，这里简单了解一下。


drawCircle 绘制圆形: 三个入参分别是圆心坐标 Offset、半径 double 、 画笔 Paint。


另外，Paint 默认是填充样式，如下左图会填满内部；可以将 style 设置为 PaintingStyle.stroke变成线型模式，如下右图：



@override
void paint(Canvas canvas, Size size) {
  Paint paint = Paint();
  canvas.drawCircle(Offset(100, 100), 50, paint);
  paint.style = PaintingStyle.stroke;
  canvas.drawCircle(Offset(250, 100), 50, paint);
}





drawRect 绘制矩形：两个入参分别是矩形 Rect、画笔 Paint。
drawRRect 绘制圆角矩形：两个入参分别是矩形 RRect、画笔 Paint。




Paint paint = Paint();
paint.style = PaintingStyle.stroke;
paint.strokeWidth = 2;
// 绘制矩形
Rect rect = Rect.fromCenter(center: Offset(100, 100), width: 100, height: 80);
canvas.drawRect(rect, paint);
// 绘制圆角矩形
paint.style = PaintingStyle.fill;
RRect rrect = RRect.fromRectXY(rect.translate(150, 0), 8, 8);
canvas.drawRRect(rrect, paint);





drawOval 绘制椭圆：两个入参分别是矩形 Rect、画笔 Paint。
drawArc 绘制圆弧：五个入参分别是矩形 RRect、起始弧度 double、扫描弧度 double、是否闭合 bool、画笔 Paint。




Paint paint = Paint();
paint.strokeWidth = 2;
// 绘制椭圆
Rect overRect = Rect.fromCenter(center: Offset(100, 100), width: 100, height: 80); 
canvas.drawOval(overRect, paint);
// 绘制圆弧
canvas.drawArc(overRect.translate(150, 0), 0, pi*1.3,true,paint);




4. 本章小结

本章主要介绍了如果在 Flutter 中通过 Canvas 自定义绘制内容。界面就相当于一张白纸、绘制接口方法就相当于画笔，使用已经存在的组件固然简单，但学会自己控制画笔绘制内容可以创造更多的精彩。当然，想要精通绘制也不是一朝一夕可以达成的，但凡工艺技能，都是熟能生巧。

这里只是简单认识了在 Flutter 中使用 Canvas 绘制的方式，接下来将结合手势和绘制，完成在手指在界面上拖拽留下痕迹的绘制效果。

                        
                        
                            