前有大佬分享了用CustomPaint画一个自定义的CircleProgressBar
的文章, 今天我分享一波自定义View(CustomPaint)的一些基础知识git
画布是一个矩形区域,咱们能够控制其每一像素来绘制咱们想要的内容github
canvas 拥有多种绘制点、线、路径、矩形、圆形、以及添加图像的方法,结合这些方法咱们能够绘制出变幻无穷的画面。canvas
虽然,画布能够画这些东西,可是决定这些图形颜色、粗细表现的仍是画笔。bash
Paint很是好理解,就是咱们用来画图形的工具,咱们能够设置画笔的颜色、粗细、是否抗锯齿、笔触形状以及做画风格。工具
经过这些属性咱们能够很方便的来定制本身的UI效果,固然咱们在“做画”的过程当中能够定义多个画笔,这样更方便咱们对图形的绘制spa
canvas中有多个与绘制相关的方法,如drawLine()、drawRect()、drawOval()、drawOval()、等方法。3d
可是,仅仅使用canvas这个画布还不够,咱们还须要一个画笔paint,咱们可使用以下代码来构建paintcode
Paint _paint = Paint()
..color = Colors.blueAccent //画笔颜色
..strokeCap = StrokeCap.round //画笔笔触类型
..isAntiAlias = true //是否启动抗锯齿
..blendMode = BlendMode.exclusion //颜色混合模式
..style = PaintingStyle.fill //绘画风格,默认为填充
..colorFilter = ColorFilter.mode(Colors.blueAccent,
BlendMode.exclusion) //颜色渲染模式,通常是矩阵效果来改变的,可是flutter中只能使用颜色混合模式
..maskFilter = MaskFilter.blur(BlurStyle.inner, 3.0) //模糊遮罩效果,flutter中只有这个
..filterQuality = FilterQuality.high //颜色渲染模式的质量
..strokeWidth = 15.0; //画笔的宽度
复制代码
固然,在正常的开发中通常不会使用这么多的属性,你们能够根据须要去具体的了解和使用。cdn
如下内容基于此画笔绘制:blog
Paint _paint = new Paint()
..color = Colors.blueAccent
..strokeCap = StrokeCap.round
..isAntiAlias = true
..strokeWidth = 5.0
..style = PaintingStyle.stroke;
复制代码
void drawLine(Offset p1, Offset p2, Paint paint)
使用给定的涂料在给定点之间绘制一条线。 该行被描边,此调用忽略[Paint.style]的值。 p1
和p2
参数为两个点的坐标 , 在这两点之间绘制一条直线。
eg : canvas.drawLine(Offset(20.0, 20.0), Offset(100.0, 100.0), _paint)
复制代码
void drawPoints(PointMode pointMode, List points, Paint paint)
绘制点也是很是的简单,3个参数分别为: PointMode枚举,坐标 list 和 paint PointMode的枚举类型有三个,points(点),lines(线,隔点链接),polygon(线,相邻链接)
canvas.drawPoints(
///PointMode的枚举类型有三个,points(点),lines(线,隔点链接),polygon(线,相邻链接)
PointMode.points,
[
Offset(20.0, 130.0),
Offset(100.0, 210.0),
Offset(100.0, 310.0),
Offset(200.0, 310.0),
Offset(200.0, 210.0),
Offset(280.0, 130.0),
Offset(20.0, 130.0),
],
_paint..color = Colors.redAccent);
复制代码
为了方便演示,咱们在上面定义了7个点,第一个和最后一个点重合。
而后咱们设置PointMode为points看下效果。
而后咱们把PointMode改成lines
PointMode为lines时,两个点相互链接,也就是说第一个和第二个点链接,第三个跟第四个链接,若是最后只有一个点就舍弃不链接了,在咱们的例子中有7个点,因此图中只有三条连线。
而后咱们把PointMode改成lines
对,你看的没有错跟上面绘制线段的效果是同样的,相邻点互相链接。
void drawCircle(Offset c, double radius, Paint paint)
参数分别为:圆心的坐标、半径和paint便可。 圆形是否填充或描边(或二者)由Paint.style
控制。
//绘制圆 参数(圆心,半径,画笔)
canvas.drawCircle(
Offset(100.0, 350.0),
30.0,
_paint
..color = Colors.greenAccent
..style = PaintingStyle.stroke //绘画风格改成stroke
);
复制代码
在这里我将画笔Paint的style改为了stroke 而后咱们将画笔style改为fill (填充) ,fill也是画笔的style的默认值.
void drawOval(Rect rect, Paint paint)
绘制一个轴对称的椭圆形 参数为一个矩形和画笔paint.
//使用左上和右下角坐标来肯定矩形的大小和位置,椭圆是在这个矩形之中内切的
Rect rect1 = Rect.fromPoints(Offset(150.0, 200.0), Offset(300.0, 250.0));
canvas.drawOval(rect1, _paint);
复制代码
在前面咱们已经讲过了使用Rect即可确认这个矩形的大小和位置。
其实,Rect也有多种构建方式:
fromPoints(Offset a, Offset b)
使用左上和右下角坐标来肯定矩形的大小和位置
fromCircle({ Offset center, double radius })
使用圆的圆心点坐标和半径和肯定外切矩形的大小和位置
fromLTRB(double left, double top, double right, double bottom)
使用矩形左边的X坐标、矩形顶部的Y坐标、矩形右边的X坐标、矩形底部的Y坐标来肯定矩形的大小和位置
fromLTWH(double left, double top, double width, double height)
使用矩形左边的X坐标、矩形顶部的Y坐标矩形的宽高来肯定矩形的大小和位置
复制代码
void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint)
首先仍是须要Rect来确认圆弧的位置,还须要开始的弧度、结束的弧度、是否使用中心点绘制(圆弧是否向中心闭合)、以及paint.
根据定义,一周的弧度数为2πr/r=2π,360°角=2π弧度,所以,1弧度约为57.3°,即57°17’44.806’’,1°为π/180弧度,近似值为0.01745弧度,周角为2π弧度,平角(即180°角)为π弧度,直角为π/2弧度。
度 | 弧度 |
---|---|
0° | 0 |
30° | π/6 |
45° | π/4 |
60° | π/3 |
90° | π/2 |
120° | 2π/3 |
180° | π |
270° | 3π/2 |
360° | 2π |
//绘制圆弧
// Rect来确认圆弧的位置,还须要开始的弧度、结束的弧度、是否使用中心点绘制、以及paint弧度
Rect rect2 = Rect.fromCircle(center: Offset(200.0, 50.0), radius: 80.0);
canvas.drawArc(rect2, 0.0, 0.8, false, _paint);
复制代码
const PI = 3.1415926;
Rect rect2 = Rect.fromCircle(center: Offset(200.0, 50.0), radius: 80.0);
canvas.drawArc(rect2, 0.0, PI / 2, false, _paint);
复制代码
定义π为3.1415926,定义开始的角度为0°扫过的角度为PI / 2(90°),设置userCenter为false
void drawRRect(RRect rrect, Paint paint)
使用RRect肯定矩形大小及弧度,使用paint来完成绘制。
RRect构建起来也很是的方便,直接使用fromRectAndRadius便可
RRect.fromRectAndRadius(rect, radius)
rect依然用来表示矩形的位置和大小,radius用来表示圆角的大小。
//用Rect构建一个边长50,中心点坐标为100,100的矩形
Rect rect = Rect.fromCircle(center: Offset(100.0, 150.0), radius: 50.0);
//根据上面的矩形,构建一个圆角矩形
RRect rrect = RRect.fromRectAndRadius(rect, Radius.circular(20.0));
canvas.drawRRect(rrect, _paint);
复制代码
将圆角的半径设置为边长(从20改为50)试一下:
void drawDRRect(RRect outer, RRect inner, Paint paint)
和drawRRect相似,使用RRect肯定内部、外部矩形大小及弧度,使用paint来完成绘制。
//绘制两个矩形
Rect rect1 = Rect.fromCircle(center: Offset(100.0, 100.0), radius: 60.0);
Rect rect2 = Rect.fromCircle(center: Offset(100.0, 100.0), radius: 40.0);
//分别绘制外部圆角矩形和内部的圆角矩形
RRect outer = RRect.fromRectAndRadius(rect1, Radius.circular(10.0));
RRect inner = RRect.fromRectAndRadius(rect2, Radius.circular(10.0));
canvas.drawDRRect(outer, inner, _paint);
复制代码
使用Rect.fromCircle来建立Rect,使用RRect.fromRectAndRadius来建立RRect
能够看到两个圆角矩形,固然咱们也能够尝试调整角度的度数大小。
//绘制两个矩形
Rect rect1 = Rect.fromCircle(center: Offset(100.0, 100.0), radius: 60.0);
Rect rect2 = Rect.fromCircle(center: Offset(100.0, 100.0), radius: 40.0);
//分别绘制外部圆角矩形和内部的圆角矩形
RRect outer = RRect.fromRectAndRadius(rect1, Radius.circular(30.0));
RRect inner = RRect.fromRectAndRadius(rect2, Radius.circular(5.0));
canvas.drawDRRect(outer, inner, _paint);
复制代码
你甚至能够调整角度的大小使两个矩形都变成圆来造成一个圆环.
void drawPath(Path path, Paint paint)
绘制路径,首先须要一个要绘制的路径path,而后就是这个paint了。
方法名 | 做用 |
---|---|
moveTo | 将路径起始点移动到指定的位置 |
relativeMoveTo | 相对于当前位置移动到 |
lineTo | 从当前位置链接指定点 |
relativeLineTo | 相对当前位置链接到 |
arcTo | 曲线 |
conicTo | 贝塞尔曲线 |
add** | 添加其余图形,如addArc,在路径是添加圆弧 |
contains | 路径上是否包括某点 |
transfor | 给路径作matrix4变换 |
combine | 结合两个路径 |
close | 关闭路径,链接路径的起始点 |
reset | 重置路径,恢复到默认状态 |
eg:
//新建了一个path,而后将路径起始点移动到坐标(100,100)的位置
Path path = new Path()..moveTo(100.0, 100.0);
path.lineTo(200.0, 200.0);
canvas.drawPath(path, _paint);
复制代码
首先新建了一个path,而后将路径起始点移动到坐标(100,100)的位置, 而后从这个位置链接(200,200)的点.
咱们也能够绘制多个路径:
Path path = new Path()..moveTo(100.0, 100.0);
path.lineTo(200.0, 200.0);
path.lineTo(100.0, 300.0);
path.lineTo(150.0, 350.0);
path.lineTo(150.0, 500.0);
canvas.drawPath(path, _paint);
复制代码
void arcTo(Rect rect, double startAngle, double sweepAngle, bool forceMoveTo)
rect
咱们都知道了,是一个矩形,startAngle
是开始的弧度,sweepAngle
是结束的弧度 重点介绍一下forceMoveTo
. forceMoveTo:
例如:
Path path = new Path()..moveTo(100.0, 100.0);
Rect rect = Rect.fromCircle(center: Offset(200.0, 200.0), radius: 60.0);
path.arcTo(rect, 0.0, 3.14, false);
canvas.drawPath(path, _paint);
复制代码
由于forceMoveTo此时为false,因此从起始点到曲线的起始点画出了直线路径, 改成true能够看到,由于启动了一个新的子路径,因此那条线段没有了:
固然,你甚至能够用贝塞尔曲线直接画一个圆:
Rect rect = Rect.fromCircle(center: Offset(200.0, 200.0), radius: 60.0);
path.arcTo(rect, 0.0, 3.14*2, false);
canvas.drawPath(path, _paint);
复制代码
void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3)
var width = 200;
var height = 300;
path.moveTo(width / 2, height / 4);
path.cubicTo((width * 6) / 7, height / 9, (width * 13) / 13,
(height * 2) / 5, width / 2, (height * 7) / 12);
canvas.drawPath(path, _paint);
Path path2 = new Path();
path2.moveTo(width / 2, height / 4);
path2.cubicTo(width / 7, height / 9, width / 21, (height * 2) / 5,
width / 2, (height * 7) / 12);
canvas.drawPath(path2, _paint);
复制代码
看一下效果:
而后咱们改变paint的样式:
canvas.drawPath(path, _paint);
替换为:
canvas.drawPath(
path,
_paint
..style = PaintingStyle.fill
..color = Colors.red);
复制代码
咱们将画笔的颜色改为红色,样式改成填充:
void drawColor(Color color, BlendMode blendMode)
咱们先绘制一个圆:
canvas.drawCircle(Offset(100.0, 100.0), 50.0, _paint);
复制代码
canvas.drawCircle(Offset(100.0, 100.0), 50.0, _paint);
canvas.drawColor(Colors.red, BlendMode.color); // 添加这行
复制代码
能够看到,圆的颜色变成了红色, 咱们还能够改变BlendMode, 例如:BlendMode.colorDodge
void drawImage(Image image, Offset p, Paint paint)
将给定的[image]以其左上角的[偏移量]绘制到画布中 首先咱们须要获取本地图片文件,而后绘制图片便可
全文相关代码已提交到 github