我们在做自定义View的时候,很多时候都会用到Path,即路径,今天总结一下Path有哪些,以及他们的常用方法。
Path常用方法:
方法 | 作用 | 备注 |
moveTo | 移动起点 | 移动下一次操作的起点位置 |
lineTo | 连接直线 | 连接上一个点到当前点之间的直线 |
setLastPoint | 设置终点 | 重置最后一个点的位置 |
close | 闭合路径 | 从最后一个点连接最初的一个点,形成一个闭合区域 |
addRect | 添加矩形 | 添加矩形到当前Path |
addRoundRect | 添加圆角矩形 | 添加圆角矩形到当前Path |
addOval | 添加椭圆 | 添加椭圆到当前Path |
addCircle | 添加圆 | |
addPath | 添加路径 | |
addArc | 添加圆弧 | |
arcTo | 绘制圆弧 | 附加到路径中 |
isEmpty | 是否为空 | |
isRect | 是否为矩形 | |
set | 替换路劲 | 用新的路劲替换当前路劲的所有内容 |
offset | 偏移路劲 | 对当前的路劲进行偏移 |
quadTo | 贝塞尔曲线 | 二次贝塞尔曲线的方法 |
cubicTo | 贝塞尔曲线 | 三次贝塞尔曲线的方法 |
rMoveTo,rlineTo,rQuadTo,rCubicTo | 不带r的方法是基于原点坐标系(偏移量),带r的基于当前点坐标系(偏移量) | |
op | 布尔操作 | 对两个Path进行布尔运算(交集,并集)等操作 |
setFillType | 填充模式 | 设置Path的填充模式 |
getFillType | 填充模式 | 获取Path的填充模式 |
isInverseFillType | 是否逆填充 | 判断是否是逆填充模式 |
toggleInverseFillType | 相反模式 | 切换相反的填充模式 |
incReserve | 提示方法 | 提示Path还有多少个点等待加入 |
computeBounds | 计算边界 | 计算Path的路劲 |
reset,rewind | 重置路劲 | 清除Path中的内容(reset相当于new Path , rewind 会保留Path的数据结构) |
transform | 矩阵操作 | 矩阵变换 |
Path方法使用详解:
使用Path不仅可以绘制简单的图形(如圆形,矩形,直线等),也可以绘制复杂一些的图形(如正多边形,五角星等),还有绘制裁剪和绘制文本都会用到Path。由于方法比较多,我这里分组来讲下。
moveTo , lineTo , setLastPoint , close
先创建画笔:
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10);
paint.setColor(Color.parseColor("#FF0000"));
1、lineTo
首先我们来看看lineTo,如果你直接moveTo 将看不出效果。
Path path = new Path();
path.lineTo(200,200);
path.lineTo(400,0);
canvas.drawPath(path,paint);
为了方便大家好观察坐标的变化,我在屏幕上画出了网格,每块网格的宽高都是100。由于第一次之前没有过操作,所以默认点就是原点(屏幕左上角),第一次lineTo就是坐标原点到(200,200)之间的直线。第二次lineTo就是上一次结束点位置(200,200)到(400,0)点之间的直线。
2、moveTo 和setLastPoint
moveTo(float x, float y)
setLastPoint(float dx, float dy)
这两个方法在作用上有相似之处,却是两个不同的东西,具体参考下表:
方法名 | 作用 | 是否影响之前的操作 | 是否影响之后的操作 |
moveTo | 移动下一次操作的起点位置 | 否 | 是 |
setLastPoint | 改变上一次操作点的位置 | 是 | 是 |
来看看下面的例子:
Path path = new Path();
path.lineTo(200, 200);
path.moveTo(300,300);
path.lineTo(400, 0);
canvas.drawPath(path, paint);
Path path = new Path();
path.lineTo(200, 200);
path.setLastPoint(300,100);
path.lineTo(400, 0);
canvas.drawPath(path, paint);
当我们绘制线条之前,调用moveTo 和 setLastPoint效果是一样的,都是对坐标原点(0,0)进行操作。setLastPoint是重置上一次操作的最后一点,在执行完第一次lineTo的时候,最后一个点就是(200,200),setLastPoint更改(200,200)为(300,100),所以在执行的时候就是(300,100)到(400, 0)之间的连线了。
3、close
close方法连接最后一个点和最初一个点(如果两个点不重合)形成一个闭合的图形。
path.moveTo(100,100);
path.lineTo(500,100);
path.lineTo(300,400);
path.close();
canvas.drawPath(path, paint);
上图中可以看到lineTo(500,100)直线和lineTo(300,400)直线,而close方法就是连接(300,400),(100,100)两点,形成一个闭合的区域。
注意:close的作用的封闭路径,如果连接最后一个点和最初一个点任然无法形成闭合的区域,那么close什么也不做。
quadTo,cubicTo
二次贝塞尔曲线以及三次贝塞尔曲线。
1、quadTo
public void quadTo(float x1, float y1, float x2, float y2)
quadTo方法其中 (x1,y1) 为控制点,(x2,y2)为结束点。
path.moveTo(100,400);
path.quadTo(300, 100, 400, 400);
canvas.drawPath(path, paint);
2、cubicTo
public void cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)
cubicTo方法比quadTo方法多了一个点坐标,那么其中(x1,y1) 为控制点,(x2,y2)为控制点,(x3,y3) 为结束点。
path.moveTo(100, 400);
path.cubicTo(100, 400, 300, 100, 400, 400);
canvas.drawPath(path, paint);
绘制的图形和上面的quadTo绘制的图形是一样的。我们去掉moveTo来看看运行的效果图:
如果你想了解贝塞尔曲线公式,请链接这里
addXxx和arcTo
主要是向Path中添加基本图形以及区分addArc和arcTo
1、添加基本图形
各个添加基本图形的方法参数中,有一个Path.Direction dir。这是个什么东东呢?Direction的意思是方向,指导,趋势。点进去跟一下你会发现Direction是一个枚举类型(Enum)分别有CW(顺时针),CCW(逆时针)两个常量。那么它的作用主要有以下两点:
1.在添加图形时确定闭合顺序(各个点的记录顺序)
2.对自相交图形的渲染结果有影响
2、addPath
public void addPath(Path src)
public void addPath(Path src, float dx, float dy)
public void addPath(Path src, Matrix matrix)
addPath方法就是将两个路径合并到一起。第二个方法的dx,dy指的是偏移量,第三个方法是添加到当前path之前先使用Matrix进行变换。来看看下面例子:
Path path = new Path();
path.addRect(100,100,400,300, Path.Direction.CW);
Path src=new Path();
src.addCircle(300,300,100, Path.Direction.CW);
path.addPath(src,0,100);
canvas.drawPath(path, paint);
3、addArc与arcTo
方法名字上面看,这两个方法都是与圆弧有关,那么他们之间肯定是有区别的:
addArc 添加一个圆弧到Path 直接添加一个圆弧到path中,和上一次操作点无关
arcTo 添加一个圆弧到Path 添加一个圆弧到path中,如果圆弧的起点和上次操作点坐标不同就连接两个点
startAngle表示开始圆弧度数(0度与X轴方向对齐,顺时针移动,弧度增大)。
注意:sweepAngle表示运动了多少弧度,并不是结束弧度。
forceMoveTo表示“是否强制使用moveTo”,也就是说是否使用moveTo将上一次操作点移动到圆弧的起点坐标。默认是false。
forceMoveTo | 含义 |
true | 将最后一个点移动到圆弧起点,即不连接最后一个点与圆弧起点 |
false | 不移动,而是连接最后一个点与圆弧起点(注意之前没有操作的话,不会连接原点) |
示例:
path.lineTo(200, 200);
RectF rectF = new RectF(100, 100, 400, 400);
path.arcTo(rectF, 0, 270, true);
// path.addArc(rectF,0,270);和上面一句等价
canvas.drawPath(path, paint);
我们把 path.arcTo(rectF, 0, 270, true);改成 path.arcTo(rectF, 0, 270, false);,来看看效果图:
offset
public void offset(float dx, float dy)
public void offset(float dx, float dy, Path dst)
这个方法就是对Path进行一段平移,正方向和X轴,Y轴方向一致(如果dx为正数则向右平移,反之向左平移;如果dy为正则向下平移,反之向上平移)。我们看到第二个方法多了一个dst,这个又是一个什么玩意呢,其实参数das是存储平移后的path的,当dst中存在内容时,dst中原有的内容会被清空,而存放平移后的path。
FillType
public void setFillType(Path.FillType ft)
public Path.FillType getFillType()
setFillType方法中的参数Path.FillType为枚举类型:
FillType值 | 含义 |
FillType.WINDING | 取path所有所在区域 默认值 |
FillType.EVEN_ODD | 取path所在并不相交区域 |
FillType.INVERSE_WINDING | 取path所有未占区域 |
FillType.INVERSE_EVEN_ODD | 取path未占或相交区域 |
下面通过几个实例说明:
setFillType
WINDING:
Path path = new Path();
path.addCircle(300,200,100, Path.Direction.CW);
path.addCircle(200,200,100, Path.Direction.CW);
path.setFillType(Path.FillType.WINDING);
canvas.drawPath(path, paint);
EVEN_ODD:
INVERSE_WINDING:
INVERSE_EVEN_ODD:
isInverseFillType
是否是逆填充模式:WINDING 和 EVEN_ODD 返回false;
INVERSE_WINDING 和 INVERSE_EVEN_ODD 返回true;
toggleInverseFillType
切换相反的填充模式,如果填充模式为WINDING则填充模式为INVERSE_WINDING,反之为WINDING模式;如果填充模式为EVEN_ODD则填充模式为INVERSE_EVEN_ODD,反之为EVEN_ODD模式。
举个例子:
Path path = new Path();
path.addCircle(300,200,100, Path.Direction.CW);
path.addCircle(200,200,100, Path.Direction.CW);
path.setFillType(Path.FillType.INVERSE_EVEN_ODD);
path.toggleInverseFillType();
canvas.drawPath(path, paint);
效果图和上面EVEN_ODD模式一模一样。