小菜最近在学习自定义 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 研究还不深入,有很多方法还没有尝试,有错误的地方希望多多指导!

Flutter 34: 图解自定义 View 之 Canvas (一)的更多相关文章

  1. Flutter 35: 图解自定义 View 之 Canvas (二)

    小菜前几天整理了以下 Canvas 的部分方法,今天小菜继续学习 Canvas 第二部分. drawXXX drawShadow 绘制阴影 drawShadow 用于绘制阴影,第一个参数时绘制一个图形 ...

  2. Flutter 36: 图解自定义 View 之 Canvas (三)

    小菜继续学习 Canvas 的相关方法: drawVertices 绘制顶点 小菜上次没有整理 drawVertices 的绘制方法,这次补上:Vertice 即顶点,通过绘制多个顶点,在进行连线,多 ...

  3. 安卓自定义View进阶-Canvas之画布操作 转载

    安卓自定义View进阶-Canvas之画布操作 转载 https://www.gcssloop.com/customview/Canvas_Convert 本来想把画布操作放到后面部分的,但是发现很多 ...

  4. Android查缺补漏(View篇)--自定义View利器Canvas和Paint详解

    上篇文章介绍了自定义View的创建流程,从宏观上给出了一个自定义View的创建步骤,本篇是上一篇文章的延续,介绍了自定义View中两个必不可少的工具Canvas和Paint,从细节上更进一步的讲解自定 ...

  5. 自定义View之Canvas使用

    自定义View的绘制流程一般都是这样:提前创建好Paint对象,重写onDraw(),把绘制代码卸载ondraw()里面,大致如下: Paint paint = new Paint(); @Overr ...

  6. 自定义View(4)Canvas和Paint常用绘制函数

    画布Canvas 在Android下进行2D绘图需要Canvas类的支持,它位于"android.graphics.Canvas"包下,直译过来为画布的意思,用于完成在View上的 ...

  7. Android 自定义 View 圆形进度条总结

    Android 自定义圆形进度条总结 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 微信公众号:牙锅子 源码:CircleProgress 文中如有纰漏,欢迎大家留言指出. 最近 ...

  8. Android自定义View学习笔记(一)

    绘制基础 参考:HenCoder Android 开发进阶: 自定义 View 1-1 绘制基础 Paint详解 参考:HenCoder Android 开发进阶: 自定义 View 1-2 Pain ...

  9. Android 自定义View之自绘控件

    首先要提前声明一下,我对于自定义View的理解并不是很深,最近啃了几天guolin博主写的关于自定义View的博客,讲的非常棒,只不过涉及到源码和底层的一些东西,我自己就懵逼了,目前只是会了关于自定义 ...

随机推荐

  1. [dart学习]第五篇:操作符

    前言:本系列内容假设读者有一定的编程基础,如了解C语言.python等. 本节一起来学习dart的操作符,直接拷贝官网的操作符描述表如下: Description Operator unary pos ...

  2. IEnumerable和IQueryable口的区别

    IQueryable: 动态表达式树拼接查询语句,把拼接后查询语句进行执行:Execute触发,延迟加载IEnumerable:对内存中的数据,动态拼接查询语句,进行查询:ToList触发,延迟加载: ...

  3. JAVA 基础编程练习题45 【程序 45 被 9 整除】

    45 [程序 45 被 9 整除] 题目:判断一个素数能被几个 9 整除 package cskaoyan; public class cskaoyan45 { public static void ...

  4. 关于运维之故障复盘篇-Case Study

    关于故障的事后复盘,英文名 Case Study是非常有必要做的,当然是根据故障的级别,不可能做到每个故障都Case Study,除非人员和时间充足: 文档能力也是能力的一种,一般工程师的文档能力比较 ...

  5. 一条语句kill 多条mysql语句

    If information_schema.processlist doesn’t exist on your version of MySQL, this works in a linux scri ...

  6. DELL服务器管理工具和RACADM介绍

    DELL服务器管理工具和RACADM介绍 一.Dell服务器管理工具介绍 Dell对服务器(DELL PowerEdge)的管理主要提供了三种管理工具,分别是Dell Remote Access Co ...

  7. Unity3d 烘培lightingmap 注意的2点.

    1.在Qulity里面设置合适的灯光数量.否则,你会发现烘培出来的场景,有些灯光没有起作用. 2.在导入模型时候,注意勾选:Generate Lightingmap .  否则,模型没办法烘培. 3. ...

  8. Flutter 实现简单搜索功能

    先建立一个主文件,继承StatelessWidget,然后在home属性中加入SearchBarDemo,这是一个自定义的Widget,主要代码都在这个文件中. import 'package:flu ...

  9. Java中get()方法和set()方法如何使用?

    在java中,为了保证数据的安全性,我们会把数据定义为private等(私有.封装),如果想要调用就会用到set()方法与get方法或者构造函数方法.这里说的是第一种方法,set()与get(),既然 ...

  10. rqnoj PID95:多多看DVD(加强版)

    题目描述 多多进幼儿园了,今天报名了.只有今晚可以好好放松一下了(以后上了学后会很忙).她的叔叔决定给他买一些动画片DVD晚上看.可是爷爷规定他们只能在一定的时间段L看完.(因为叔叔还要搞NOIP不能 ...