小菜最近在学习自定义 View,刚了解了一下 Paint 画笔的神奇之处,现在学习一下 Canvas 画布的神秘之处。Flutter 提供了众多的绘制方法,小菜接触不深,尽量都尝试一下。
drawColor 需要传入两个参数,第一个为色值,第二个为混合模式,有众多混合模式供选择,但注意使用混合模式后会与绘制其上的其他 View 颜色混合像素。
canvas.drawColor(Colors.pinkAccent, BlendMode.srcIn);
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);
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 可以用来绘制圆弧甚至配合 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 用来绘制矩形,Flutter 提供了多种绘制矩形方法:
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 绘制圆角矩形,Flutter 提供了多种绘制方法:
// 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 绘制嵌套矩形,第一个参数为外部矩形,第二个参数为内部矩形,可用上述多种设置圆角矩形方式;最后一个参数为 Paint 画笔,且 PaintingStyle 为 fill 时填充的是两个矩形之间的范围。
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 绘制圆形,仅需设置原点及半径即可;
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 绘制椭圆方式很简单,主要绘制一个矩形即可;
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 用来绘制路径,Flutter 提供了众多路径方法,小菜尝试几种常用的方法:
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 研究还不深入,有很多方法还没有尝试,有错误的地方希望多多指导!