说起canvas,可能很多人都有过了解和使用. 本文主要意指详解canvas的能力.

准备工作

如果你正准备学习flutter的canvas, 那么不妨和笔者一样打开idea. 然后紧跟着内容自己也敲一遍.

ps: 友情提醒,自己敲一遍, 影响更深刻哦~

首先创建一个widget,在其中返回一个CustomPaint

1
2
3
4
5
6
Widget build(BuildContext context) {
return CustomPaint(
size: const Size(100, 100),
painter: _DemoPainter(),
);
}

其次,我们需要准备好画笔. 正所谓工欲善其事,必先利其器.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/// 创建画画的载体
class _DemoPainter extends CustomPainter {
// 创建画布
final Paint _paint = Paint()..color = Colors.blue;

@override
void paint(Canvas canvas, Size size) {
// 这里去正式的绘制
}

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

准备好工具后,我们还需要知道我们画布是根据笛卡尔坐标系的.以我们的手机为例.当手机正对我们时, 手机的左上角即为原点, 从左上角到右上角即为正x轴,从左上角到左下角即为正y轴.
image
在了解完这些基础概念后,让我们一起详细的探索canvas的世界吧!

探索

drawLine

drawLine(Offset p1, Offset p2, Paint paint) 即绘制一条直线, 其中, p1为初始点,p2为终点来绘制一条线段.
image

drawCircle

drawCircle(Offset c, double radius, Paint paint) 可以在画布上绘制一个圆. 其中, c 代表者圆心, radius 代表者半径. paint 自然代表着我们之前生成的画笔了(以下不再赘述该属性). 这里的代码代表着我们以往右和下分别偏移50dp的点为圆心, 以50为半径绘制圆.

1
canvas.drawCircle(Offset(50.0, 50.0), 50.0, _paint);

image

drawRect

drawRect(Rect rect, Paint paint) 可以用来绘制一个矩形.rect代表了矩形的描述*. 它可以通过五种命名构造方法来简单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 绘制矩形
// 从偏移的中心出发,中心即为矩形中心,以长宽绘制矩型
// Rect.fromCenter(center: center, width: width, height: height);
//
// 从原点出发,离原点往右left,往下top单位为矩形左上角,往右right,往下bot// tom为右下角画矩型
// Rect.fromLTRB(left, top, right, bottom);
//
// 从center为圆心,直径为长宽画矩形。实际上也就是正方形
// Rect.fromCircle(center: center, radius: radius);
//
// 从原点往右left, 往下top为矩形左上角, width、height为长宽绘制
// Rect.fromLTWH(left, top, width, height);
//
// a.b分别为矩形的对角点
// Rect.fromPoints(a, b);
canvas.drawRect(Rect.fromCircle(center: Offset.zero, radius: 100), _paint);

image
ps: drawRRect 实际上和drawRect差不多, 它用来绘制圆角矩形. 有兴趣的可以自己尝试一下或者参考一下结尾中的源码.
image

drawOval

drawOval(Rect rect, Paint paint) 可以绘制一个椭圆形.它提供了rect 的参数. rect 是用来描述一个矩形的形状. 而绘制的椭圆也就是以中心为圆心,轴对其.边贴边的一个椭圆.这里绘制的是一个以往右下各偏移50dp为中心,长为50,宽为100的矩阵画椭圆.

1
canvas.drawOval(Rect.fromCenter(center: Offset(50, 50), width: 100, height: 50), _paint);

image

drawArc

drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint) 可以绘制圆弧.. 其中rect比较熟悉 这里不赘述. startAngle就是绘制的起始角度.这里使用的是弧度制, 也就是0 -> 2pi. sweepAngle是扫过点角度, userCenter是是否连接圆心.
这里为了方便演示useCenter 的区别.需要改一下画笔的属性

1
2
3
4
5
// 画笔的粗细
_paint.strokeWidth = 5;
// 画笔改成只画边缘不填充.这里的区别就是圆弧是否填充
_paint.style = PaintingStyle.stroke;
canvas.drawArc(Rect.fromCircle(center: Offset(50, 50), radius: 50), 0, pi, true, _paint);

userCenter 为true:

image

userCenter 为false:

image

drawPaint

drawPaint(Paint paint) 即使用画笔填充画布颜色.比较简单不赘述.
image

drawPath

drawPath(Path path, Paint paint) 可以通过路径去绘制. 这里算是比较重要也比较实用的一个属性,很多绘制都会通过path方法去绘制.我们这里采用绘制三角形的方法来讲解它.

1
2
3
4
5
6
7
8
9
10
Path path = Path();
/// 首先移到原点
path.moveTo(0, 0);
/// 然后直线连接到(0,100)
path.lineTo(0, 100);
/// 最后再连接到(100,100)
path.lineTo(100, 100);
/// 最后连接到原点闭合
path.close();
canvas.drawPath(path, _paint);

image

drawPoints

drawPoints(PointMode pointMode, List points, Paint paint) 可以理解为点线图,其中pointMode包括三种:points、lines以及polygon.

1
2
3
4
5
6
7
8
List<Offset> points = const [
Offset(0, 0),
Offset(10, 10),
Offset(20, 20),
Offset(30, 30),
Offset(40, 40),
];
canvas.drawPoints(PointMode.lines, points, _paint);

points:

image
lines:

image
polygon:


我们可以分别对比下,三种模式下绘制的差别.简单来说, points模式会绘制每个点.lines会取每两个点为一个线段,如果是奇数的话,则会忽略最后一个点.polygon则是绘制一条线段

drawText

drawText实际上不是canvas提供的api, 不过这里也引入这个概念. 我们需要创建TextPainter 对象,然后通过该对象去实现绘制.

1
2
3
4
5
6
TextPainter painter = TextPainter(
text: TextSpan(
text: '绘制文字', style: TextStyle(color: Colors.black, fontSize: 20)),
textDirection: TextDirection.ltr,
)..layout();
painter.paint(canvas, Offset.zero);

other

实际上,canvas还包括了很多的api.包括绘制Image、点九图、图集等等.这里不妨自己做个尝试.也算是一个家庭作业吧~ 一起努力吧!骚年!!

源码

github.com/weniner/flutter_demo/

结语

这里是WeninerIo,热爱生活且热爱旅行.如果你对这次的分享感兴趣又或者有什么疑惑, 不妨评论区留言 + 关注.期待下一次更好的相遇.