在 Flutter 中自定义 View 有两种方式:

  1. 组合已有控件
  2. 自定义绘制

如何自定义绘制

有两个类做这件事情:

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。
  • CustomPaint :会在绘制阶段提供一个 Canvas 画布
  • CustomPainter : 具体的画笔, 可配置画笔的颜色,路径等
CustomPaint(
  painter: Sky(),
  child: Center(
    child: Text(
      'Once upon a time...', style: const TextStyle( fontSize: 40.0, fontWeight: FontWeight.w900, color: Color(0xFFFFFFFF), ), ), ), ) 复制代码

当在绘制阶段时, CustomPaint 首先会调用 painter 在画布上进行绘制, 然后再绘制它的 child 控件, child 绘制完成之后会调用 foregroundPainter 进行绘制. 画布的坐标系和 CustomPaint 的坐标系匹配. CustomPaint 有个 Size 属性标识将绘制多大的区域, 绘制时这个 Size 属性将会传递到 CustomPainter 的 paint 方法中, 具体的绘制就在paint 方法中进行, void paint(Canvas canvas, Size size); 的方法签名中的两个参数:

  • canvas: 用于绘制的画布, 注意: 该画布是应用所有控件都在使用的, 所以通过这个画布其实是可以绘制充满屏幕的内容的
  • size: 表示应该绘制的区域大小, 每次绘制都应该限制在这个区域内, 否则可能会覆盖了其他控件的绘制结果

实例一

绘制一个矩形和圆角:

Flutter 自定义绘制 View 随笔 第1张
Widget build(BuildContext context) {
  return CustomPaint( painter: ColorPainter(), size: Size(300, 200), ); } 复制代码
class ColorPainter extends CustomPainter { final red = Color.fromRGBO(255, 0, 0, 1); final blue = Color.fromRGBO(0, 0, 255, 1); @override void paint(Canvas canvas, Size size) { final paint = Paint(); final rect = Rect.fromLTRB(0.0, 0.0, size.width, size.height); // 注意这一句 canvas.clipRect(rect); paint.color = blue; canvas.drawRect(rect, paint); paint.color = red; canvas.drawCircle(Offset.zero, size.height, paint); } @override bool shouldRepaint(CustomPainter oldDelegate) { return false; } } 复制代码
  • 定义了绘制区域大小, 为 CustomPaint 中的 size 属性
    final rect = Rect.fromLTRB(0.0, 0.0, size.width, size.height); 复制代码
  • 绘制矩形区域
    canvas.drawRect(rect, paint);
复制代码
  • 绘制圆形
    • 圆心偏移量为: 0, 也就是 CustomPaint 的原点
    • 半径为区域的高度
    canvas.drawCircle(Offset.zero, size.height, paint);
复制代码

最需要注意的地方我觉得是 canvas.clipRect(rect); 这句. 这句表示只绘制给定的区域中的内容. 如果不写这句, 效果就是这样:

Flutter 自定义绘制 View 随笔 第2张

为什么会这样呢 ?

其实这就是 Size 这个参数的重要性, 因为 Canvas 是被所有控件公有的, 如果我们绘制时不指定区域大小, 那在进行一些形状的绘制时就会出现超出区域的问题.

实例二: 绘制一个带波纹的 CardView

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄