flutter 用 CustomPaint 绘制自定义图案

什么是CustomPaint?

在Android中,有时候我们需要使用 Canvas 和 Paint 来进行绘制一些复杂的图形,在 Flutter 中,当然也有可以让你自由绘制的方案,他就是 CustomPaint。

CustomPaint 也是一个 Widget,你可以把它嵌到视图树的任意一个节点位置。

先看看它的常用属性:

属性 类型 说明
painter CustomPainter 背景画笔,绘制内容会显示在child子节点后面
foregroundPainter CustomPainter 前景画笔,绘制内容会显示在child子节点前面
size Size 设置绘制区域的大小。如果有child,则忽略该参数,且绘制区域为child的尺寸
isComplex bool 是否复杂的绘制,如果是,Flutter会应用一些缓存策略来减少重复渲染的开销。默认false
willChange bool 和isComplex配合使用,当启用缓存时,该属性代表在下一帧中绘制是否会改变。默认false
child Widget 没错,CustomPaint是可以包含一个子节点的

CustomPaint是一个继承自SingleChildRenderObjectWidget的控件,不能用setState的方式来刷新它。

painter就是我们的主绘制工具,它是一个CustomPainterforegroundPainter是用来绘制前景的工具;

size为画布大小,这个size会传递给Painter

isComplexwillChange 是告诉Flutter你的CustomPaint是否复杂到需要使用cache相关的功能;

child属性我们一般不填,即使你是想要在你的CustomPaint上添加一些其他的布局,也不建议放在child属中性,因为你会发现你并不会得到你想要的结果。

CustomPainter 是一个抽象类,你需要继承它实现自己的逻辑。

class MyPainter extends CustomPainter {

  @override
  paint(Canvas canvas, Size size)  {
       // do
  }

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

继承 CustomPainter 最重要的是实现 paint(Canvas canvas, Size size)shouldRepaint(CustomPainter oldDelegate) 这两个函数。

  • paint() 中是绘制逻辑,可以在这获得画布 Canvas 和 画布的大小 Size
  • shouldRepaint() 返回 true 才会进行重绘,否则就只会绘制一次。你可以通过一些条件判断来决定是否每次绘制,这样能够节约系统资源。

例如:

@override
  void paint(Canvas canvas, Size size) {
    final outerThickess = max(trackWidth, max(progressWidth, thumbSize));
    Size constrainedSize = new Size(
      size.width - outerThickess,
      size.height - outerThickess
    );
    // paint track.
    final center = new Offset(size.width / 2, size.height /2);
    final radius = min(constrainedSize.width, constrainedSize.height) / 2;
    canvas.drawCircle(center, radius, trackPaint);

    // paint progress.
    final progressAngle = 2 * pi * progressPercent;
    canvas.drawArc(new Rect.fromCircle(
      center: center,
      radius: radius
    ), -pi / 2, progressAngle, false, progressPaint);

    // paint thumb.
    final thumbAngle = 2 * pi * thumbPosition - (pi / 2);
    final thumbX = cos(thumbAngle) * radius;
    final thumbY = sin(thumbAngle) * radius;
    final thumbCenter = new Offset(thumbX, thumbY) + center;
    final thumbRadius = thumbSize / 2;
    canvas.drawCircle(thumbCenter, thumbRadius, thumbPaint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    return true;
  }

这里简单的列一下,一些常用的canvas绘制API:

// 绘制弧线
drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint)
// 绘制图片
drawImage(Image image, Offset p, Paint paint) 
// 绘制圆
drawCircle(Offset c, double radius, Paint paint) 
// 绘制线条
drawLine(Offset p1, Offset p2, Paint paint) 
// 绘制椭圆
drawOval(Rect rect, Paint paint)
// 绘制文字
drawParagraph(Paragraph paragraph, Offset offset)
// 绘制路径
drawPath(Path path, Paint paint) 
// 绘制点
drawPoints(PointMode pointMode, List<Offset> points, Paint paint)
// 绘制Rect
drawRect(Rect rect, Paint paint) 
// 绘制阴影
drawShadow(Path path, Color color, double elevation, bool transparentOccluder)

1、绘制直线

void paint(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..isAntiAlias = true
      ..color = Colors.pink
      ..strokeWidth = 10
      ..style = PaintingStyle.fill;
    Paint paint1 = Paint()
      ..isAntiAlias = true
      ..color = Colors.blue
      ..strokeWidth = 10
      ..style = PaintingStyle.fill;
    Paint paint2 = Paint()
      ..isAntiAlias = true
      ..color = Colors.green
      ..strokeWidth = 10
      ..style = PaintingStyle.fill;
    /// Offset(),横纵坐标偏移
    canvas.drawLine(Offset(85, 100), Offset(285, 100), paint);
    canvas.drawLine(Offset(85, 100), Offset(200, 300), paint1);
    canvas.drawLine(Offset(285, 100), Offset(200, 300), paint2);
  }

2、绘制弧线

void paint(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..isAntiAlias = true
      ..color = Colors.green
      ..strokeCap = StrokeCap.round
      ..strokeWidth = 10
      ..style = PaintingStyle.stroke;
    Paint paint1 = Paint()
      ..isAntiAlias = true
      ..color = Colors.blue
      ..strokeCap = StrokeCap.round
      ..strokeWidth = 10
      ..style = PaintingStyle.stroke;
    /// Offset(),横纵坐标偏移
    /// void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint)
    /// Rect来确认圆弧的位置, 开始的弧度、结束的弧度、是否使用中心点绘制(圆弧是否向中心闭合)、以及paint.
    final center = new Offset(170, 200);
    canvas.drawArc(new Rect.fromCircle(
        center: center,
        radius: size.width / 2
    ), -pi / 2, 2 * pi * 0.5, false, paint);
    canvas.drawArc(new Rect.fromCircle(
        center: Offset(170, 300),
        radius: size.width / 2
    ), pi / 2, 2 * pi * 0.5, false, paint1);
  }

flutter 用CustomPaint画一个自定义的CircleProgressBar

3、绘制圆

 Paint paint = Paint()
      ..isAntiAlias = true
      ..color = Colors.green
      ..strokeCap = StrokeCap.round
      ..strokeWidth = 10
      ..style = PaintingStyle.fill;
    Paint paint1 = Paint()
      ..isAntiAlias = true
      ..color = Colors.blue
      ..strokeCap = StrokeCap.round
      ..strokeWidth = 10
      ..style = PaintingStyle.stroke;
      canvas.drawCircle(Offset(150.0, 200.0), 50.0, paint1);
      canvas.drawCircle(Offset(150.0, 350.0), 50.0, paint);

flutter 用CustomPaint画一个自定义的CircleProgressBar

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!