Flutter 34: 图解自定义 View 之 Canvas (一)

简介: 0 基础学习 Flutter,第三十四步:自定义 View 第二节~

      小菜最近在学习自定义 View,刚了解了一下 Paint 画笔的神奇之处,现在学习一下 Canvas 画布的神秘之处。Flutter 提供了众多的绘制方法,小菜接触不深,尽量都尝试一下。

Canvas 画布

drawColor 绘制背景色

      drawColor 需要传入两个参数,第一个为色值,第二个为混合模式,有众多混合模式供选择,但注意使用混合模式后会与绘制其上的其他 View 颜色混合像素。

canvas.drawColor(Colors.pinkAccent, BlendMode.srcIn);
drawPoints 绘制点/线

      drawPoints 不仅可以绘制点,还可以绘制点与点的连线;PointMode 包括 points 点 / lines 线 / polygon 多边形;注意 lines 为每两点之间的连线,若为奇数个点,最后一个没有与之相连的点。

// 绘制点
canvas.drawPoints(
  PointMode.points,
  [
    Offset(30.0, 30.0), Offset(60.0, 30.0),
    Offset(90.0, 30.0), Offset(90.0, 60.0),
    Offset(60.0, 60.0), Offset(30.0, 60.0)
  ],
  Paint()..strokeWidth = 4.0);
canvas.drawPoints(
  PointMode.points,
  [
    Offset(160.0, 30.0), Offset(190.0, 30.0),
    Offset(220.0, 30.0), Offset(220.0, 60.0),
    Offset(190.0, 60.0), Offset(160.0, 60.0)
  ],
  Paint()..strokeWidth = 4.0..strokeCap = StrokeCap.round);
// 绘制线
canvas.drawPoints(
    PointMode.lines,
    [
      Offset(30.0, 100.0), Offset(60.0, 100.0),
      Offset(90.0, 100.0), Offset(90.0, 130.0),
      Offset(60.0, 130.0), Offset(30.0, 130.0)
    ],
    Paint()..strokeWidth = 4.0..strokeCap = StrokeCap.round);
// 绘制多边形
canvas.drawPoints(
    PointMode.polygon,
    [
      Offset(160.0, 100.0), Offset(190.0, 100.0),
      Offset(220.0, 100.0), Offset(220.0, 130.0),
      Offset(190.0, 130.0), Offset(160.0, 130.0)
    ],
    Paint()..strokeWidth = 4.0..strokeCap = StrokeCap.round);

drawLine 绘制线
canvas.drawLine(Offset(30.0, 90.0), Offset(Screen.width - 30.0, 90.0),
    Paint()..strokeWidth = 4.0);
canvas.drawLine(Offset(30.0, 120.0), Offset(Screen.width - 30.0, 120.0),
    Paint()..strokeWidth = 4.0..strokeCap = StrokeCap.round);
canvas.drawLine(Offset(30.0, 150.0), Offset(Screen.width - 30.0, 150.0),
    Paint()..strokeWidth = 4.0..strokeCap = StrokeCap.square);
drawArc 绘制弧/饼

      drawArc 可以用来绘制圆弧甚至配合 Paint 绘制饼状图;drawArc 的第一个参数为矩形范围,即圆弧所在的圆的范围,若非正方形则圆弧所在的圆会拉伸;第二个参数为起始角度,0.0 为坐标系 x 轴正向方形;第三个参数为终止角度,若超过 2*PI,则为一个圆;第四个参数为是否由中心出发,false 时只绘制圆弧,true 时绘制圆饼;第五个参数即 Paint 画笔,可通过 PaintingStyle 属性绘制是否填充等;

const PI = 3.1415926;
canvas.drawArc(Rect.fromCircle(center: Offset(60.0, 60.0), radius: 80.0),
    0.0, PI / 2, false,
    Paint()..color = Colors.white..strokeCap = StrokeCap.round..strokeWidth = 4.0..style = PaintingStyle.stroke);
canvas.drawArc(Rect.fromCircle(center: Offset(200.0, 60.0), radius: 80.0),
    0.0, PI / 2, false,
    Paint()..color = Colors.white..strokeWidth = 4.0..style = PaintingStyle.fill);
canvas.drawArc(Rect.fromCircle(center: Offset(90.0, 160.0), radius: 80.0),
    0.0, PI * 2 / 3, true,
    Paint()..color = Colors.white..strokeWidth = 4.0..style = PaintingStyle.stroke);
canvas.drawArc(Rect.fromCircle(center: Offset(250.0, 160.0), radius: 80.0),
    0.0, PI * 2 / 3, true,
    Paint()..color = Colors.white..strokeWidth = 4.0..style = PaintingStyle.fill);
canvas.drawArc(Rect.fromLTWH(30.0, 300.0, 200.0, 100.0),
    0.0, 5.0, true,
    Paint()..color = Colors.white..style = PaintingStyle.fill);
canvas.drawArc(Rect.fromPoints(Offset(260.0, 260.0), Offset(320.0, 420.0)),
    0.0, 5.0, true,
    Paint()..color = Colors.white..style = PaintingStyle.fill);

drawRect 绘制矩形

      drawRect 用来绘制矩形,Flutter 提供了多种绘制矩形方法:

  1. Rect.fromPoints 根据两个点(左上角点/右下角点)来绘制;
  2. Rect.fromLTRB 根据以屏幕左上角为坐标系圆点,分别设置上下左右四个方向距离;
  3. Rect.fromLTWH 根据设置左上角的点与矩形宽高来绘制;
  4. Rect.fromCircle 最特殊,根据圆形绘制正方形;
canvas.drawRect(Rect.fromPoints(Offset(30.0, 30.0), Offset(150.0, 100.0)),
    Paint()..color = Colors.white..strokeWidth = 4.0..style = PaintingStyle.stroke);
canvas.drawRect(Rect.fromPoints(Offset(210.0, 30.0), Offset(330.0, 100.0)),
    Paint()..color = Colors.white..style = PaintingStyle.fill);
canvas.drawRect(Rect.fromLTRB(30.0, 140.0, 150.0, 210.0),
    Paint()..color = Colors.white);
canvas.drawRect(Rect.fromLTWH(210.0, 140.0, 120.0, 70.0),
    Paint()..color = Colors.white);
canvas.drawRect(Rect.fromCircle(center: Offset(90.0, 300.0), radius: 60.0),
    Paint()..color = Colors.white..strokeWidth = 4.0..style = PaintingStyle.stroke);

drawRRect 绘制圆角矩形

      drawRRect 绘制圆角矩形,Flutter 提供了多种绘制方法:

  1. RRect.fromLTRBXY 前四个参数用来绘制矩形位置,剩余两个参数绘制固定 x/y 弧度;
  2. RRect.fromLTRBR 前四个参数用来绘制矩形位置,最后一个参数绘制 Radius 弧度;
  3. RRect.fromLTRBAndCorners 前四个参数用来绘制矩形位置,剩余四个可选择参数,根据需求设置四个角 Radius 弧度,可不同;
  4. RRect.fromRectXY 第一个参数绘制矩形,可以用上面介绍的多种矩形绘制方式,剩余两个参数绘制固定 x/y 弧度;
  5. RRect.fromRectAndRadius 第一个参数绘制矩形,可以用上面介绍的多种矩形绘制方式,最后一个参数绘制 Radius 弧度;
  6. RRect.fromRectAndCorners第一个参数绘制矩形,可以用上面介绍的多种矩形绘制方式,剩余四个可选择参数,根据需求设置四个角 Radius 弧度,最为灵活。
// RRect.fromLTRBXY 方式
canvas.drawRRect(
    RRect.fromLTRBXY(30.0, 30.0, 150.0, 100.0, 8.0, 8.0),
    Paint()..color = Colors.white..strokeWidth = 4.0..style = PaintingStyle.stroke);
canvas.drawRRect(
    RRect.fromLTRBXY(210.0, 30.0, 330.0, 100.0, 8.0, 18.0),
    Paint()..color = Colors.white..style = PaintingStyle.fill);
// RRect.fromLTRBR 方式
canvas.drawRRect(
    RRect.fromLTRBR(30.0, 140.0, 150.0, 210.0, Radius.circular(8.0)),
    Paint()..color = Colors.white..strokeWidth = 4.0..style = PaintingStyle.stroke);
// RRect.fromLTRBAndCorners 方式
canvas.drawRRect(
    RRect.fromLTRBAndCorners(210.0, 140.0, 330.0, 210.0,
        topLeft: Radius.circular(5.0),
        topRight: Radius.circular(20.0),
        bottomRight: Radius.circular(5.0),
        bottomLeft: Radius.circular(20.0)),
    Paint()..color = Colors.white..strokeWidth = 4.0..style = PaintingStyle.stroke);
// RRect.fromRectAndCorners 方式
canvas.drawRRect(
    RRect.fromRectAndCorners(Rect.fromLTWH(30.0, 260.0, 120.0, 70.0),
        topLeft: Radius.circular(5.0),
        topRight: Radius.circular(20.0),
        bottomRight: Radius.circular(5.0),
        bottomLeft: Radius.circular(20.0)),
    Paint()..color = Colors.white..strokeWidth = 4.0..style = PaintingStyle.stroke);
// RRect.fromRectAndRadius 方式
canvas.drawRRect(
    RRect.fromRectAndRadius(Rect.fromLTWH(210.0, 260.0, 120.0, 70.0),
        Radius.elliptical(8.0, 18.0)),
    Paint()..color = Colors.white..strokeWidth = 4.0..style = PaintingStyle.stroke);
// RRect.fromRectXY 方式
canvas.drawRRect(
    RRect.fromRectXY(
        Rect.fromCircle(center: Offset(90.0, 420.0), radius: 60.0),
        8.0, 8.0),
    Paint()..color = Colors.white..strokeWidth = 4.0..style = PaintingStyle.stroke);

drawDRRect 绘制嵌套矩形

      drawDRRect 绘制嵌套矩形,第一个参数为外部矩形,第二个参数为内部矩形,可用上述多种设置圆角矩形方式;最后一个参数为 Paint 画笔,且 PaintingStylefill 时填充的是两个矩形之间的范围。

canvas.drawDRRect(
    RRect.fromRectXY(
        Rect.fromCircle(center: Offset(90.0, 420.0), radius: 60.0), 8.0, 8.0),
    RRect.fromRectXY(
        Rect.fromCircle(center: Offset(90.0, 420.0), radius: 54.0), 8.0, 8.0),
    Paint()..color = Colors.whit..strokeWidth = 3.0
      ..style = PaintingStyle.stroke);
canvas.drawDRRect(
    RRect.fromRectXY(
        Rect.fromCircle(center: Offset(270.0, 420.0), radius: 60.0), 8.0, 8.0),
    RRect.fromRectXY(
        Rect.fromCircle(center: Offset(270.0, 420.0), radius: 54.0), 8.0, 8.0),
    Paint()..color = Colors.white..strokeWidth = 3.0
      ..style = PaintingStyle.fill);

drawCircle 绘制圆形

      drawCircle 绘制圆形,仅需设置原点及半径即可;

canvas.drawCircle(Offset(90.0, 420.0), 60.0,
    Paint()..color = Colors.white..strokeWidth = 3.0
      ..style = PaintingStyle.stroke);
canvas.drawCircle(Offset(270.0, 420.0), 60.0,
    Paint()..color = Colors.white..strokeWidth = 3.0
      ..style = PaintingStyle.fill);

drawOval 绘制椭圆

      drawOval 绘制椭圆方式很简单,主要绘制一个矩形即可;

canvas.drawOval(Rect.fromLTRB(30.0, 30.0, 150.0, 100.0),
    Paint()..color = Colors.white..strokeWidth = 3.0
      ..style = PaintingStyle.stroke);
canvas.drawOval(Rect.fromLTRB(210.0, 30.0, 330.0, 100.0),
    Paint()..color = Colors.white..strokeWidth = 3.0
      ..style = PaintingStyle.fill);

drawPath 绘制路径

      drawPath 用来绘制路径,Flutter 提供了众多路径方法,小菜尝试几种常用的方法:

  1. moveTo() 即从当前坐标点开始,不设置时默认为屏幕左上角位置;
  2. lineTo() 即从起点绘制到设置的新的点位;
  3. close() 即最后的点到起始点连接,但对于中间绘制矩形/弧等时最后不会相连;
  4. reset() 即清空连线;
  5. addRect() 添加矩形连线;
  6. addOval() 添加弧线,即贝塞尔(二阶)曲线;
  7. cubicTo() 添加弧线,即贝塞尔(三阶)曲线;
  8. relativeMoveTo() 相对于移动到当前点位,小菜认为与 moveTo 相比整个坐标系移动;
  9. relativeLineTo() 相对连接到当前点位,并将坐标系移动到当前点位;
canvas.drawPath(
    Path()
      ..moveTo(30.0, 100.0)..lineTo(120.0, 100.0)
      ..lineTo(90.0, 130.0)..lineTo(180.0, 130.0)
      ..close(),
    Paint()
      ..color = Colors.white..strokeWidth = 3.0
      ..style = PaintingStyle.stroke);
canvas.drawPath(
    Path()
      ..moveTo(200.0, 100.0)..lineTo(290.0, 100.0)
      ..lineTo(260.0, 130.0)..lineTo(350.0, 130.0)
      ..close(),
    Paint()
      ..color = Colors.white..strokeWidth = 3.0
      ..style = PaintingStyle.fill);
canvas.drawPath(
    Path()
      ..moveTo(30.0, 170.0)..lineTo(120.0, 170.0)
      ..lineTo(90.0, 210.0)..lineTo(180.0, 210.0)
      ..addRect(Rect.fromLTWH(180.0, 210.0, 120.0, 70.0))
      ..addOval(Rect.fromLTWH(180.0, 210.0, 120.0, 70.0))
      ..moveTo(230.0, 170.0)..lineTo(320.0, 170.0)
      ..close(),
    Paint()
      ..color = Colors.white..strokeWidth = 3.0..style = PaintingStyle.stroke);
canvas.drawPath(
    Path()
      ..arcTo(Rect.fromCircle(center: Offset(60, 300), radius: 80), -PI / 6,
          PI * 2 / 3, false),
    Paint()
      ..color = Colors.white..strokeWidth = 3.0..style = PaintingStyle.stroke);
canvas.drawPath(
    Path()
      ..moveTo(210.0, 300.0)
      ..cubicTo(210.0, 390.0, 270.0, 330.0, 330.0, 300.0),
    Paint()
      ..color = Colors.black..strokeWidth = 3.0..style = PaintingStyle.stroke);

      小菜绘制了一个基本的坐标系来比较一下 moveTo()/lineTo()relativeMoveTo()/relativeLineTo() 的区别:

canvas.drawPath(
    Path()
      ..relativeMoveTo(30.0, 30.0)..relativeLineTo(120.0, 30.0)
      ..relativeLineTo(90.0, 60.0)..relativeLineTo(180.0, 60.0),
    Paint()
      ..color = Colors.blue..strokeWidth = 6.0
      ..style = PaintingStyle.stroke);
canvas.drawPath(
    Path()
      ..moveTo(30.0, 30.0)..lineTo(120.0, 30.0)
      ..lineTo(90.0, 60.0)..lineTo(180.0, 60.0),
    Paint()
      ..color = Colors.orange..strokeWidth = 6.0
      ..style = PaintingStyle.stroke);


      小菜对自定义 View 研究还不深入,有很多方法还没有尝试,有错误的地方希望多多指导!

目录
相关文章
|
Dart 前端开发
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
510 75
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
Dart 前端开发 容器
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
495 18
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
UED 开发者 容器
Flutter&鸿蒙next 的 Sliver 实现自定义滚动效果
Flutter 提供了强大的滚动组件,如 ListView 和 GridView,但当需要更复杂的滚动效果时,Sliver 组件是一个强大的工具。本文介绍了如何使用 Sliver 实现自定义滚动效果,包括 SliverAppBar、SliverList 等常用组件的使用方法,以及通过 CustomScrollView 组合多个 Sliver 组件实现复杂布局的示例。通过具体代码示例,展示了如何实现带有可伸缩 AppBar 和可滚动列表的页面。
630 1
Flutter 自定义组件继承与调用的高级使用方式
本文深入探讨了 Flutter 中自定义组件的高级使用方式,包括创建基本自定义组件、继承现有组件、使用 Mixins 和组合模式等。通过这些方法,您可以构建灵活、可重用且易于维护的 UI 组件,从而提升开发效率和代码质量。
488 1
|
前端开发 开发者
深入探索 Flutter 鸿蒙版的画笔使用与高级自定义动画
本文深入探讨了 Flutter 中的绘图功能,重点介绍了 CustomPainter 和 Canvas 的使用方法。通过示例代码,详细讲解了如何绘制自定义图形、设置 Paint 对象的属性以及实现高级自定义动画。内容涵盖基本绘图、动画基础、渐变动画和路径动画,帮助读者掌握 Flutter 绘图与动画的核心技巧。
318 1
|
Dart UED 开发者
Flutter&鸿蒙next中的按钮封装:自定义样式与交互
在Flutter应用开发中,按钮是用户界面的重要组成部分。Flutter提供了多种内置按钮组件,但有时这些样式无法满足特定设计需求。因此,封装一个自定义按钮组件变得尤为重要。自定义按钮组件可以确保应用中所有按钮的一致性、可维护性和可扩展性,同时提供更高的灵活性,支持自定义颜色、形状和点击事件。本文介绍了如何创建一个名为CustomButton的自定义按钮组件,并详细说明了其样式、形状、颜色和点击事件的处理方法。
354 1
|
Dart 搜索推荐 API
Flutter & 鸿蒙next版本:自定义对话框与表单验证的动态反馈与错误处理
在现代移动应用开发中,用户体验至关重要。本文探讨了如何在 Flutter 与鸿蒙操作系统(HarmonyOS)中创建自定义对话框,并结合表单验证实现动态反馈与错误处理,提升用户体验。通过自定义对话框和表单验证,开发者可以提供更加丰富和友好的交互体验,同时利用鸿蒙next版本拓展应用的受众范围。
324 1
|
前端开发 vr&ar 容器
Flutter 115: 图解自定义 View 之 Canvas (四) drawParagraph
0 基础学习 Flutter,第一百一十五节:自定义 Canvas 第四节,文本绘制小结!
833 0
Flutter 115: 图解自定义 View 之 Canvas (四) drawParagraph
|
前端开发 Android开发 iOS开发
Flutter 35: 图解自定义 View 之 Canvas (二)
0 基础学习 Flutter,第三十五步:自定义 View 第三节~
4914 0
|
前端开发 Android开发 存储
Flutter 36: 图解自定义 View 之 Canvas (三)
0 基础学习 Flutter,第三十六步:自定义 View 第四节~
2383 0