如何使用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;
  }
}

實現效果:

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