如何使用Canvas draw/paint

一、如何使用Canvas draw/paint

在Android中,您可以使用Canvas在屏幕上绘制自定义形状。但是在Flutter我们要借助CustomPaint和CustomPainter类来帮助我们绘制画布,它们实现您的算法以绘制各种图案到画布。

二、CustomPaint和CustomPainter

1、CustomPaint 介绍

CustomPaint让用户能够自定义widget,它提供了canvas用户可以通过这个canvas来绘制widget,CustomPaint会先调用painter绘制背景,然后再绘制child,最后调用foregroundPainter来绘制前景,CustomPaint的定义如下

const CustomPaint({
    Key key,
    this.painter,
    this.foregroundPainter,
    this.size = Size.zero,
    this.isComplex = false,
    this.willChange = false,
    Widget child,
  }) 
  • painter:负责绘制背景的painter
  • foregroundPainter : 负责绘制前景的painter
  • size : 控件大小
  • isComplex : 是否复杂绘制,需要用cache来提高绘制效率
  • willChange : 和isComplex配合使用,当启用缓存时,该属性代表在下一帧中绘制是否会改变
  • child : 子widget

2、CustomPainter 介绍

CustomPaint的绘制过程都将会交给CustomPainter来完成,CustomPainter是个抽象类,初始化CustomPainter的时候必须要重写它的paintshouldRepaint接口,可以根据自己的场景来选择重写hitTestshouldRebuildSemantics方法。

  • paint : 每当CustomPaint需要重绘的时候都会调用此接口
  • shouldRepaint : 当CustomPaint被重新设置了一个新的painter后会回调此方法,CustomPaint会根据shouldRepaint的返回值来判断是否需要重新绘制ui,譬如新的painter跟旧的painter绘制的内容不一样时,此时shouldRepaint需要返回true来通知CustomPaint重新绘制。

3、Canvas 介绍

提供图形操作界面,canvas提供了各种绘制接口来绘制图形。真正的绘制是由canvas跟paint来完成的

//画圆
drawCircle(Offset c, double radius, Paint paint) → void
//画图片
drawImage(Image image, Offset p, Paint paint) → void
//画九宫图
drawImageNine(Image image, Rect center, Rect dst, Paint paint) → void
//画线
drawLine(Offset p1, Offset p2, Paint paint) → void
//画椭圆
drawOval(Rect rect, Paint paint) → void
//画文字
drawParagraph(Paragraph paragraph, Offset offset) → void
//画Rect区域
drawRect(Rect rect, Paint paint) → void
//画阴影
drawShadow(Path path, Color color, double elevation, bool transparentOccluder) → void

 4、Paint

在canvas上绘制时要使用的画笔。

  • color : 设置画笔颜色
  • isAntiAlias : 设置画笔是否扛锯齿
  • shader : 着色器,填充形状或者画线时用到,如果没设置将会使用color
  • strokeWidth : 设置画笔画线宽度
  • style :绘制模式,画线或充满

三、下面是对CustomPainter的使用


class Signature extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return new SignatureState();
  }
}

class SignatureState extends State<Signature> {
  List<Offset> _points = <Offset>[];
  Widget build(BuildContext context) {
    return new GestureDetector(
      onPanUpdate: (DragUpdateDetails details) {
        setState(() {
          RenderBox referenceBox = context.findRenderObject();
          Offset localPosition = referenceBox.globalToLocal(details.globalPosition);
          var dy = localPosition.dy;
          var dx = localPosition.dx;
          var width = referenceBox.size.width;
          var height = referenceBox.size.height;

          if(0<= dx && dx <= width && 0<= dy && dy<=height){
            _points = new List.from(_points)..add(localPosition);
          }
          //如果不添加判断,则会在全局范围内绘制
          // _points = new List.from(_points)..add(localPosition);
        });
      },
      behavior: HitTestBehavior.translucent,
      onPanEnd: (DragEndDetails details) => _points.add(null),
      child: new CustomPaint(
        painter: new SignaturePainter(_points),
      ),
    );
  }
}

class SignaturePainter extends CustomPainter {
  final List<Offset> points;

  SignaturePainter(this.points);

  @override
  void paint(Canvas canvas, Size size) {
    // TODO: implement paint
    var paint = new Paint()
      ..color = Colors.black
      ..strokeCap = StrokeCap.round
      ..strokeWidth = 5.0;
    for (int i = 0; i < points.length - 1; i++) {
      if (points[i] != null && points[i + 1] != null) {
        canvas.drawLine(points[i], points[i + 1], paint);
      }
    }
  }

  @override
  bool shouldRepaint(SignaturePainter oldDelegate) {
    // TODO: implement shouldRepaint
    return oldDelegate.points != points;
  }
}

实现效果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章