逆水行舟用力撑,一篙松劲退千寻。这篇文章主要讲述Android Canvas之Path操作相关的知识,希望能为你提供帮助。
接上篇,
Android自定义View工具:
Paint&
Canvas(二)
上一篇中介绍的Canvas绘制图形只能画一些常规图形(
圆,
椭圆,
矩形等)
,
如果想绘制更复杂的图形,
Path神器来了!
Path是什么?
Path类将多种复合路径(
多个轮廓,
如直线段、二次曲线、立方曲线)
封装在其内部的几何路径。
如何绘制Path:
通过设置Paint的Style(
FILL、STROKE、FILL_AND_STROKE)
,
然后调用canvas.drawPath(path, paint);
Path还可以用于剪切或者在路径上绘制文本(
canvas.drawTextOnPath())
。
Path有两个构造函数:
Path() // 空的构造函数
Path(Path src) //创建一个新的路径,
并且从src路径里赋值内容
【Android Canvas之Path操作】 Path常用方法一览表:
Path常用方法 | 备注 |
---|---|
线操作 | |
lineTo、rLineTo | 绘制线 |
点操作 | |
moveTo、rMoveTo | 改变后面操作的起始点位置 |
setLastPoint | 改变前面操作中最后点的位置 |
添加常规图形 | |
addRect | 绘制矩形 |
addRoundRect | 绘制圆角矩形 |
addCircle | 绘制圆 |
addOval | 绘制椭圆 |
addArc、arcTo | 绘制圆弧 |
闭合path | |
close | 如果连接Path起点和终点能形成一个闭合图形, 则会将起点和终点连接起来形成一个闭合图形 |
贝塞尔曲线 | |
quadTo、rQuadTo、cubicTo、rCubicTo | 贝塞尔曲线 |
- 线操作
lineTo(float x, float y) //添加当前点到目标点(
x,
y)
构成的直线到path
rLineTo(float dx, float dy) //基于当前坐标系,
即以path最后的那个点
//为坐标系原点(
0,0)
,
如果前面没有path的点,
默认是屏幕左上角(
0,0)
.
注: lineTo、rLineTo起始点默认是屏幕左上角的坐标系原点( 0,0) !
示例:
//设置Paint
Paint paint =
new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10f);
//设置Path
Path path =
new Path();
//屏幕左上角(
0,0)
到(
200,400)
画一条直线
path.lineTo(200, 400);
//(200, 400)到(
400,600)
画一条直线
path.lineTo(400, 600);
//以(
400,600)
为起始点(
0,0)
偏移量为(
400,600)
画一条直线,
//其终点坐标实际在屏幕的位置为(
800,1200)
path.rLineTo(400, 600);
canvas.drawPath(path, mPaint);
效果图:
![Android Canvas之Path操作](http://img.readke.com/220418/000T1O02-0.jpg)
文章图片
- 点操作
moveTo(float x, float y) //改变接下来操作的起点位置为(
x,y)
rMoveTo(float dx, float dy) //接下来要操作的起点位置为(
x+
dx,y+
dy)
setLastPoint(float dx, float dy) //改变前一步操作点的位置,
会改变前一步的操作
先来看 moveTo和rMoveTo的区别 , 示例:
//初始化Paint
Paint paint =
new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10f);
//初始化Path
Path path =
new Path();
//将坐标系原点从(
0,0)
移动到(
100,100)
path.moveTo(100, 100);
//画从(
100,100)
到(
400,400)
之间的直线
path.lineTo(400, 400);
//path.rMoveTo(0, 100);
//暂时注释
path.lineTo(400, 800);
canvas.drawPath(path, mPaint);
效果图:
![Android Canvas之Path操作](http://img.readke.com/220418/000T11351-1.jpg)
文章图片
上面代码中, 打开注释的path.rMoveTo(0, 100), 意为下一步操作起点位置由( 400,400) 变为( 400+ 0,400+ 100) 即为( 400,500) , 效果图:
![Android Canvas之Path操作](http://img.readke.com/220418/000T15Y3-2.jpg)
文章图片
接下来看下, moveTo和setLastPoint的区别, 同样用上面的代码,加上path.setLastPoint(100, 800), 如下:
//初始化Paint
Paint paint =
new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10f);
//初始化Path
Path path =
new Path();
//将坐标系原点从(
0,0)
移动到(
100,100)
path.moveTo(100, 100);
//画从(
100,100)
到(
400,400)
之间的直线
path.lineTo(400, 400);
//新加的setLastPoint
path.setLastPoint(100, 800);
path.lineTo(400, 800);
canvas.drawPath(path, mPaint);
效果图:
![Android Canvas之Path操作](http://img.readke.com/220418/000T12D4-3.jpg)
文章图片
虚线本来是没设置setLastPoint之前的路径, 设置setLastPoint( 100,800) 后, 影响到了前一步lineTo( 400,400) 操作, 变成了lineTo( 100,800) , 最后结果就变成了红颜色的path路径, 可以得出结论: moveTo影响的是后面操作的起点位置, 不会影响之前的操作; 而 setLastPoint改变前一步操作最后一个点的位置, 不仅影响前一步操作, 同时也会影响后一步操作!
- 绘制常规图形
//绘制圆
addCircle(float x, float y, float radius, Direction dir)
//绘制椭圆
addOval(RectF oval, Direction dir)
addOval(float left, float top, float right, float bottom, Direction dir)
//绘制矩形
addRect(RectF rect, Direction dir)
addRect(float left, float top, float right, float bottom, Direction dir)
//绘制圆角矩形
addRoundRect(RectF rect, float rx, float ry, Direction dir)
addRoundRect(float left, float top, float right, float bottom, float rx, float ry,Direction dir)
addRoundRect(RectF rect, float[] radii, Direction dir)
addRoundRect(float left, float top, float right, float bottom, float[] radii,Direction dir)
所有方法里面都有一个共同的参数Direction :
Direction | 备注 |
---|---|
Path.Direction.CCW | counter-clockwise , 沿逆时针方向绘制 |
Path.Direction.CW | clockwise , 沿顺时针方向绘制 |
//初始化Paint
Paint paint =
new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2f);
paint.setTextSize(40f);
//初始化Path
Path path =
new Path();
//以(
600,600)
为圆心,
300为半径绘制圆
//Path.Direction.CW顺时针绘制圆 Path.Direction.CCW逆时针绘制圆
path.addCircle(600, 600, 300, Path.Direction.CW);
//沿path绘制文字
canvas.drawTextOnPath("
痛苦最好是别人的,
快乐才是自己的;
麻烦将是暂时的,
朋友总是永恒的。"
, path, 0, 0, paint);
canvas.drawPath(path, paint);
效果图:
![Android Canvas之Path操作](http://img.readke.com/220418/000T13Q8-4.jpg)
文章图片
效果很明显, 设置为Path.Direction.CW时, 文字沿顺时针绘制; 设置为Path.Direction.CCW时, 文字沿逆时针绘制。
绘制常规图形示例:
//初始化Paint
Paint paint =
new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10f);
Path path =
new Path();
//以(
400,200)
为圆心,
半径为100绘制圆
path.addCircle(400, 200, 100, Path.Direction.CW);
//绘制椭圆
RectF rectF =
new RectF(100, 350, 500, 600);
//第一种方法绘制椭圆
path.addOval(rectF, Path.Direction.CW);
//第二种方法绘制椭圆
path.addOval(600, 350, 1000, 600, Path.Direction.CW);
//绘制矩形
RectF rect =
new RectF(100, 650, 500, 900);
//第一种方法绘制矩形
path.addRect(rect, Path.Direction.CW);
//第一种方法绘制矩形
path.addRect(600, 650, 1000, 900, Path.Direction.CCW);
//绘制圆角矩形
RectF roundRect =
new RectF(100, 950, 300, 1100);
//第一种方法绘制圆角矩形
path.addRoundRect(roundRect, 20, 20, Path.Direction.CW);
//第二种方法绘制圆角矩形
path.addRoundRect(350, 950, 550, 1100, 10, 50, Path.Direction.CCW);
//第三种方法绘制圆角矩形
//float[] radii中有8个值,
依次为左上角,
右上角,
右下角,
左下角的rx,ry
RectF roundRectT =
new RectF(600, 950, 800, 1100);
path.addRoundRect(roundRectT, new float[]{50, 50, 50, 50, 50, 50, 0, 0}, Path.Direction.CCW);
//第四种方法绘制圆角矩形
path.addRoundRect(850, 950, 1050, 1100,new float[]{0, 0, 0, 0,50, 50, 50, 50}, Path.Direction.CCW);
canvas.drawPath(path, paint);
效果图:
![Android Canvas之Path操作](http://img.readke.com/220418/000T1EN-5.jpg)
文章图片
绘制圆弧:
//绘制圆弧
addArc(RectF oval, float startAngle, float sweepAngle)
addArc(float left, float top, float right, float bottom, float startAngle,float sweepAngle)//forceMoveTo:
是否强制将path最后一个点移动到圆弧起点,
//true是强制移动,
即为不连接两个点;
false则连接两个点
arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)
arcTo(RectF oval, float startAngle, float sweepAngle)
arcTo(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean forceMoveTo)
addArc和arcTo都是添加圆弧到path中, 不过他们之间还是有区别的: addArc是直接添加圆弧到path中, 而arcTo会判断要绘制圆弧的起点与绘制圆弧之前path中最后的点是否是同一个点, 如果不是同一个点的话, 就会连接两个点。
示例:
//在(400, 200, 600, 400)区域内绘制一个300度的圆弧
RectF rectF =
new RectF(400, 200, 600, 400);
path.addArc(rectF, 0, 300);
//在(400, 600, 600, 800)区域内绘制一个90度的圆弧,
并且不连接两个点
RectF rectFTo =
new RectF(400, 600, 600, 800);
path.arcTo(rectFTo, 0, 90, true);
//等价于path.addArc(rectFTo, 0, 90);
canvas.drawPath(path, paint);
效果图:
![Android Canvas之Path操作](http://img.readke.com/220418/000T15562-6.jpg)
文章图片
修改一下代码:
//在(400, 200, 600, 400)区域内绘制一个300度的圆弧
RectF rectF =
new RectF(400, 200, 600, 400);
path.addArc(rectF, 0, 300);
//在(400, 600, 600, 800)区域内绘制一个90度的圆弧,
并且连接两个点
RectF rectFTo =
new RectF(400, 600, 600, 800);
path.arcTo(rectFTo, 0, 90,false);
//等价于path.arcTo(rectFTo, 0, 90);
canvas.drawPath(path, paint);
对比发现我们只是将arcTo最后一个参数变成了false, 即连接绘制圆弧之前path的最后一个点和绘制圆弧的起点, 效果图:
![Android Canvas之Path操作](http://img.readke.com/220418/000T14c0-7.jpg)
文章图片
- 闭合path
path.close();
如果path的终点和起始点不是同一个点的话, close()连接这两个点, 形成一个封闭的图形, 示例:
//初始化Paint
Paint paint =
new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10f);
//初始化Path
Path path =
new Path();
//将坐标原点移动到(
300,300,)
path.moveTo(300, 300);
//连接(300, 300)和(300, 600)成一条线
path.lineTo(300, 600);
//连接(300, 600)和(600, 600)成一条线
path.lineTo(600, 600);
//path.close();
暂时注释
canvas.drawPath(path, paint);
效果图:
![Android Canvas之Path操作](http://img.readke.com/220418/000T13c4-8.jpg)
文章图片
修改一下代码, 将上面的path.close()打开, 效果图:
![Android Canvas之Path操作](http://img.readke.com/220418/000T11435-9.jpg)
文章图片
可以调用close()后, 连接了path的起始点和终点形成了一个封闭图形!
贝塞尔曲线内容较多, 放在下一篇了!
推荐阅读
- [ZZ]AppiumForWindows 菜鸟计划合集
- Android实战——RxJava2解锁图片三级缓存框架
- appium使用教程(一 环境搭建)-------------2.安装部署
- 在Android Studio中打开Android Device Monitor时报错的解决方法
- 一键生成 Android 录屏 gif 的脚本
- 迅为开发板知识库-4418开发板编译Android镜像内容分享
- Android底层有一定的认识,研究过相关的Android源码
- 安卓工程的启动过程
- Android性能优化的一些方案