一. 前言
1.Path的定义
路径,即无数个点连起来的线条。
2. Path的作用
设置绘制的顺序 或者区域。
3. 应用场景
绘制复杂图形(如心形,五角星形);
二. 基础
1. 开放路径和闭合路径
开放路径时不闭合的。
闭合路径是闭合的。
2. 如何判断点是在图形内还是图形外
① 奇偶规则
从任意位置p作一条射线,根据与图形边相交的点数进行判断。
a. 若相交的点数是奇数,则认为p为图形内部点。
b. 若相交的点数是偶数,则认为p为图形外部点。
② 非零环饶数规则
从任意位置p作一条射线,当p点沿射线方向移动时,对在每个方向上穿过射线的边计数。
a. 每当图形的边从右到左穿过射线时,环绕数加1;从左到右时,环绕数减1。
b. 若环绕数为非零,则p为内部点,否则为外部点。
三. 具体使用
1. 对象创建
1 2 3 4 5
|
Path path = new Path();
|
2. 设置路径
采用moveTo()、setLastPoint()、lineTo()、close()
组合
1 2 3 4 5 6 7 8 9 10 11 12 13
|
moveTo(float x, float y) ;
lineTo(float x, float y) ;
close() ;
|
moveTo和setLastPoint的区别:
类型 |
是否影响起点 |
是否影响之前操作 |
moveTo() |
是 |
否 |
setLastPoint() |
否 |
是 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| path.lineTo(400, 500);
path.moveTo(300, 300) ;
path.lineTo(900, 800);
path.lineTo(200, 700);
path.close();
canvas.drawPath(path, mPaint1);
path.lineTo(400, 500);
path.setLastPoint(300, 300) ;
path.lineTo(900, 800);
path.lineTo(200, 700);
path.close();
canvas.drawPath(path, mPaint1);
|

3. 重置路径
重置Path有两个方法:reset()
和rewind()
。
区别:
方法 |
是否保留FillType设置 |
是否保留原有数据结构 |
reset |
是 |
否 |
rewind |
否 |
是 |
FillType
影响显示效果;数据结构
影响重建速度
- 所以一般选择
Path.reset()
4. 添加路径
采用addXxx()、arcTo()
组合
① 添加基本图形
1> 作用:在Path路径中添加基本图形,如圆形路径,圆弧路径等。
2> 具体使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
public void addArc (RectF oval, float startAngle, float sweepAngle)
public void arcTo (RectF oval, float startAngle, float sweepAngle)
public void arcTo (RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)
addCircle(float x, float y, float radius, Path.Direction dir)
addOval(RectF oval, Path.Direction dir)
addRect(RectF rect, Path.Direction dir)
addRoundRect(RectF rect, float rx, float ry, Path.Direction dir)
|
主要说一下dir这个参数:
dir = Direction = 图形的方向,为枚举类型:
- CW:clockwise,顺时针
- CCW:counter-clockwise,逆时针
图形的方向影响的是:
- 添加图形时确定闭合顺序(各个点的记录顺序)
- 图形的渲染结果(是判断图形渲染的重要条件)
图形绘制的本质:先画点,再将点连接起来。所以,点与点之间是存在一个先后顺序的;顺时针和逆时针用于确定这些点的顺序。
3> 实例
a. 顺时针,逆时针
1 2 3 4 5 6 7 8
| canvas.translate(350, 500);
path.addRect(0, 0, 400, 400, Path.Direction.CW);
canvas.drawPath(path,mPaint1);
|

b. 加入圆形路径后会影响路径的起点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| canvas.translate(400,500); path.lineTo(-100,0); path.lineTo(-100,200); path.lineTo(200,200); path.close();
canvas.drawPath(path,paint);
canvas.translate(400,500); path.lineTo(-100,0); path.addCircle(0,0,100, Path.Direction.CCW);
path.lineTo(-100,200); path.lineTo(200,200);
path.close(); canvas.drawPath(path,paint);
|

c. 添加圆弧路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
public void addArc (RectF oval, float startAngle, float sweepAngle)
public void arcTo (RectF oval, float startAngle, float sweepAngle)
public void arcTo (RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)
|

② 添加路径
1> 作用:合并路径,即将路径1加到路径2里面
2> 具体使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public void addPath (Path src)
public void addPath (Path src, float dx, float dy)
public void addPath (Path src, Matrix matrix)
canvas.translate(350, 500);
Path pathRect = new Path(); Path pathCircle = new Path();
pathRect.addRect(-200, -200, 200, 200, Path.Direction.CW);
pathCircle.addCircle(0, 0, 100, Path.Direction.CW);
pathRect.addPath(pathCircle, 0, 200);
canvas.drawPath(pathRect,mPaint1);
|

5. 判断路径属性
采用isEmpty()、 isRect()、isConvex()、 set() 和 offset()
组合
具体使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| public boolean isEmpty ()
Path path = new Path(); path.isEmpty();
path.lineTo(100,100);
public boolean isRect (RectF rect)
path.lineTo(0,400); path.lineTo(400,400); path.lineTo(400,0); path.lineTo(0,0);
RectF rect = new RectF(); boolean b = path.isRect(rect);
public void set (Path src)
Path path = new Path(); path.addRect(-200,-200,200,200, Path.Direction.CW);
Path src = new Path(); src.addCircle(0,0,100, Path.Direction.CW);
path.set(src);
canvas.drawPath(path,mPaint);
public void offset (float dx, float dy)
public void offset (float dx, float dy, Path dst)
canvas.translate(350, 500);
path = new Path(); path.addCircle(0, 0, 100, Path.Direction.CW);
Path dst = new Path(); path.offset(400, 0, dst);
canvas.drawPath(path, mPaint1);
mPaint1.setColor(Color.RED); canvas.drawPath(dst,mPaint1);
|

6. 设置路径填充颜色
① 在Android中,有四种填充模式,均封装在Path类中
填充模式 |
介绍 |
EVEN_ODD |
奇偶规则 |
INVERSE_EVEN_ODD |
反奇偶规则 |
WINDING |
非零环绕数规则 |
INVERSE_WINDING |
反非零环绕数规则 |

② 使用方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| path.setFillType()
path.getFillType()
path.isInverseFillType()
path.toggleInverseFillType()
|
③ 具体例子
1> 奇偶规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| canvas.translate(350, 500);
path.addRect(-200, -200, 200, 200, Path.Direction.CW);
path.setFillType(Path.FillType.EVEN_ODD);
canvas.drawPath(path, mPaint1);
|

2> 非零环绕规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| canvas.translate(550, 550);
path.addRect(-400, -400, 400, 400, Path.Direction.CCW);
path.addRect(-200, -200, 200, 200, Path.Direction.CCW);
path.setFillType(Path.FillType.WINDING);
canvas.drawPath(path, mPaint1);
|

7. 布尔操作
① 作用
两个路径Path之间的运算。
② 应用场景
用简单的图形通过特定规则合成相对复杂的图形。
③ 具体使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| boolean op (Path path, Path.Op op)
path1.op(path2, Path.Op.DIFFERENCE);
boolean op (Path path1, Path path2, Path.Op op)
path3.op(path1, path2, Path.Op.DIFFERENCE)
|
之间的运算方式(即Path.Op参数)如下

举例
1 2 3 4 5 6 7 8 9 10 11 12 13
| canvas.translate(550, 550);
path1.addCircle(0, 0, 100, Path.Direction.CW); path2.addCircle(50, 0,100, Path.Direction.CW);
path1.op(path2, Path.Op.XOR);
canvas.drawPath(path1, mPaint1);
|

四. 贝塞尔曲线
1. 定义
计算曲线的数学公式
2.作用
计算并表示曲线,任何一条曲线都可以用贝塞尔曲线表示。
3. 具体使用
贝塞尔曲线可通过1数据点和若干个控制点描述
数据点:指路径的起始点和终止点;
控制点:决定了路径的弯曲轨迹;
n+1阶贝塞尔曲线 = 有n个控制点;
(1阶 = 一条直线,高阶可以拆解为多条低阶曲线)
4. 系统API
Canvas提供了画二阶 & 三阶贝塞尔曲线的方法,下面是具体方法:
1 2 3 4 5 6 7 8 9 10 11
|
quadTo(float x1, float y1, float x2, float y2)
rQuadTo(float x1, float y1, float x2, float y2)
cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)
rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3)
|
详细的贝塞尔曲线的知识可以参考贝塞尔曲线开发的艺术。
参考文章
Path类的最全面详解 - 自定义View应用系列