# Android知识总结——Path常用方法解析

## 常用API解析与示例

### 一、xxxTo方法

Path类中提供了一套xxxTo方法，其作用是从起点到终点移动path画笔并绘制线（moveTo方法只移动path画笔不绘制线），线有直线和曲线。方法汇总如下表所示

lineTo(float x, float y) 绘制直线x：终点x坐标值，y：终点y坐标值
moveTo(float x, float y) 移动画笔x：终点x坐标值，y：终点y坐标值
arcTo(RectF oval, float startAngle, float sweepAngle) 绘制圆弧oval：圆弧矩形区域，startAngle：起始角度，sweepAngle：圆弧旋转的角度
arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo) 绘制圆弧oval：圆弧矩形区域，startAngle：起始角度，sweepAngle：圆弧旋转的角度，forceMoveTo：是否在绘制圆弧前移动（moveTo）path画笔位置
arcTo(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean forceMoveTo) 绘制圆弧left、top、right、bottom组成圆弧矩形区域，startAngle：起始角度，sweepAngle：圆弧旋转的角度，forceMoveTo：是否在绘制圆弧前移动（moveTo）path画笔位置
quadTo(float x1, float y1, float x2, float y2) 绘制二阶贝塞尔曲线控制点坐标：(x1,y1)终点坐标：(x2,y2)
cubicTo(float x1, float y1, float x2, float y2,float x3, float y3) 绘制三阶贝塞尔曲线，其中控制点1坐标为(x1,y1)控制点2坐标为(x2,y2)终点坐标为(x3,y3)

#### 1.lineTo(float x, float y)

``````path.lineTo(300,300);
canvas.drawPath(path,paint);
``````

#### 2.moveTo(float x, float y)

``````path.moveTo(100,100);
path.lineTo(300,300);
canvas.drawPath(path,paint);
``````

#### 3.arcTo(RectF oval, float startAngle, float sweepAngle)

``````RectF rectF = new RectF(100,100,300,400);
path.arcTo(rectF,0,180);
canvas.drawPath(path,pathPaint);
``````

#### arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)

``````RectF rectF = new RectF(100,100,300,400);
path.moveTo(100,100);
path.arcTo(rectF,0,180,false);
path.close();
canvas.drawPath(path,pathPaint);
``````
``````RectF rectF = new RectF(100,100,300,400);
path.moveTo(100,100);
path.arcTo(rectF,0,180,true);
path.close();
canvas.drawPath(path,pathPaint);
``````
``````RectF rectF = new RectF(100,100,300,400);
path.arcTo(rectF,0,180,false);
path.close();
canvas.drawPath(path,pathPaint);
``````

#### arcTo(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean forceMoveTo)

arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)用法一样

#### 4.quadTo(float x1, float y1, float x2, float y2)

``````path.moveTo(100,100);
canvas.drawPath(path,pathPaint);
``````

#### 5.cubicTo(float x1, float y1, float x2, float y2,float x3, float y3)

``````path.moveTo(100,100);
path.cubicTo(200,0,300,90,500,100);
canvas.drawPath(path,pathPaint);
``````

``````path.moveTo(300,200);
path.cubicTo(300,200+100*0.551915024494f,200+100*0.551915024494f,300,200,300);

path.moveTo(200-20,300);
path.cubicTo(200-100*0.551915024494f-20,300,100-20,200+100*0.551915024494f,100-20,200);
canvas.drawPath(path,pathPaint);
``````

### 二、rXxxTo方法

rXxxTo方法r意思是relative，即相对的意思，方法有四个，如上图所示，其功能与对应的xxxTo方法一样，区别在于rXxxTo方法在绘制Path时是以当前path画笔位置为坐标原点，即相对于path画笔位置进行绘制，而xxxTo方法的坐标原点则与当前canvas坐标原点一致。例如，我们使用xxxTo方法

``````path.moveTo(100,100);
path.lineTo(300,300);
canvas.drawPath(path, pathPaint);
``````

``````path.moveTo(100,100);
path.rLineTo(200,200);
canvas.drawPath(path, pathPaint);
``````

addArc(RectF oval, float startAngle, float sweepAngle) 添加圆弧oval：圆弧矩形区域，startAngle：起始角度，sweepAngle：圆弧旋转的角度
addArc(float left, float top, float right, float bottom, float startAngle,float sweepAngle) 添加圆弧left、top、right、bottom组成圆弧矩形区域，startAngle：起始角度，sweepAngle：圆弧旋转的角度。ps：此方法在API 19以上有效
addOval(RectF oval, Direction dir) 添加椭圆oval：椭圆内切的矩形区域，dir：线的闭合方向（CW顺时针方向 | CCW逆时针方向）
addOval(float left, float top, float right, float bottom, Direction dir) 添加椭圆left、top、right、bottom组成椭圆内切的矩形区域，dir：线的闭合方向（CW顺时针方向 | CCW逆时针方向）
addRect(RectF rect, Direction dir) 添加矩形rect：矩形区域，dir：线的闭合方向（CW顺时针方向 | CCW逆时针方向）
addRect(float left, float top, float right, float bottom, Direction dir) 添加矩形left、top、right、bottom组成矩形区域，dir：线的闭合方向（CW顺时针方向 | CCW逆时针方向）
addRoundRect(RectF rect, float rx, float ry, Direction dir) 添加统一圆角的圆角矩形rect：矩形区域，rx：椭圆圆角的横轴半径，ry：椭圆圆角的纵轴半径，dir：线的闭合方向（CW顺时针方向 | CCW逆时针方向）
addRoundRect(float left, float top, float right, float bottom, float rx, float ry,Direction dir) 添加统一圆角的圆角矩形left、top、right、bottom组成矩形区域，rx：椭圆圆角的横轴半径，ry：椭圆圆角的纵轴半径，dir：线的闭合方向（CW顺时针方向 | CCW逆时针方向）
addPath(Path src, float dx, float dy) 添加一组平移后的Pathsrc：要添加的Path，dx：平移的x坐标，dy：平移的y坐标

#### 1.addArc(RectF oval, float startAngle, float sweepAngle)

addArc两个方法使用起来与arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)forceMoveTo设置为true效果一致，就不展开赘述了

``````path.addCircle(200,150,100, Path.Direction.CW);//顺时针绘制
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);
``````
``````path.addCircle(200,150,100, Path.Direction.CCW);//逆时针绘制
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);
``````

oval矩形区域中，添加一个内切的椭圆，绘制起始角度为0°（x轴方向），绘制方向通过dir的值而定，dirCW时顺时针绘制，dirCCW时逆时针绘制

addOval(RectF oval, Direction dir)addOval(float left, float top, float right, float bottom, Direction dir)效果是一样的，就不分开讲了

``````RectF rectF = new RectF(100,100,400,250);
canvas.drawPath(path,pathPaint);
``````

addRect(RectF rect, Direction dir)addRect(float left, float top, float right, float bottom, Direction dir)效果是一样的，就不分开讲了

``````RectF rectF = new RectF(100,100,400,250);
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);
``````

#### 5.addRoundRect(RectF rect, float rx, float ry, 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)效果是一样的，就不分开讲了

``````RectF rectF = new RectF(100,100,400,350);
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);
``````
``````RectF rectF = new RectF(100,100,400,350);
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);
``````

``````RectF rectF = new RectF(100,100,400,350);
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);
``````

``````Path copyPath = new Path();
copyPath.moveTo(100,100);
copyPath.lineTo(150,200);
copyPath.lineTo(100,250);
copyPath.close();
canvas.drawPath(path,pathPaint);
``````

#### addPath(Path src, float dx, float dy)

``````Path copyPath = new Path();
copyPath.moveTo(100,100);
copyPath.lineTo(150,200);
copyPath.lineTo(100,250);
copyPath.close();
canvas.drawPath(path,pathPaint);
``````

``````Path copyPath = new Path();
copyPath.moveTo(100,100);
copyPath.lineTo(150,200);
copyPath.lineTo(100,250);
copyPath.close();

Matrix mMatrix = new Matrix();
mMatrix.setScale(1,-1);//以x轴为中线进行翻转
mMatrix.postRotate(90);//以坐标轴原点为中心点顺时针旋转90°

canvas.drawPath(path,pathPaint);
``````

### 四、填充模式

setFillType(FillType ft) 设置Path的填充模式ft：填充类型，有EVEN_ODDINVERSE_EVEN_ODDWINDINGINVERSE_WINDING 四种模式
getFillType() 获取当前Path的填充模式
isInverseFillType() 判断当前Path填充模式是否是反向规则(INVERSE_XXX)
toggleInverseFillType() 当前Path的填充模式与其反向规则模式进行相互切换

[转]Android Path里FillType功能

### 五、其他方法

close() 封闭当前Path，连接起点终点
reset() 清空Path中的所有直线和曲线，保留填充模式设置，不保留Path上相关的数据结构
rewind() 清空Path中的所有直线和曲线，不保留填充模式设置，但会保留Path上相关的数据结构，以便高效地复用
set(Path src) 用名为src的Path替换当前的Path
op(Path path, Op op) 当前Path名为path的Path进行布尔运算（取差集、交集、并集等）op：运算逻辑，有DIFFERENCE（差集）REVERSE_DIFFERENCE（差集）INTERSECT（交集）UNION（并集）XOR（异或）五种运算逻辑可选。ps：此方法在API 19以上有效
offset(float dx, float dy) 平移当前Pathx轴上平移的距离为dxy轴上平移的距离为dy
offset(float dx, float dy, Path dst) 平移名为dst的Pathx轴上平移的距离为dxy轴上平移的距离为dy
transform(Matrix matrix) 对当前Path进行矩阵变换，矩阵为matrix（3x3矩阵）
transform(Matrix matrix, Path dst) 对名为dst的Path进行矩阵变换，矩阵为matrix（3x3矩阵）
setLastPoint(float dx, float dy) 设置终点，设置当前Path最后一个点的位置为(dx,dy)
isEmpty() 判断当前Path是否为空
isConvex() 判断当前Path围成的图形是否凸多边形。ps：此方法在API 21以上有效
isRect(RectF rect) 判断当前Path是否为矩形，如是，则将当前Path存储到新建的rect中

#### 1.op(Path path, Op op) 布尔运算

``````Path path1 = new Path();
pathPaint.setColor(Color.GREEN);
canvas.drawPath(path1,pathPaint);

Path path2 = new Path();
pathPaint.setColor(Color.RED);
canvas.drawPath(path2,pathPaint);
``````

##### DIFFERENCE（差集）

``````Path path1 = new Path();

Path path2 = new Path();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
path1.op(path2, Path.Op.DIFFERENCE);//path1与path2进行布尔运算，结果保存至path1
canvas.drawPath(path1,pathPaint);
}

//也可以这样写
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
path3.op(path1,path2,Path.Op.DIFFERENCE);//path1与path2进行布尔运算，结果保存至path3
canvas.drawPath(path3,pathPaint);
}
``````

##### REVERSE_DIFFERENCE（差集）

``````if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
path1.op(path2, Path.Op.REVERSE_DIFFERENCE);//path1与path2进行布尔运算，结果保存至path1
canvas.drawPath(path1,pathPaint);
}

//也可以这样写
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
path3.op(path1,path2,Path.Op.REVERSE_DIFFERENCE);//path1与path2进行布尔运算，结果保存至path3
canvas.drawPath(path3,pathPaint);
}
``````
##### INTERSECT（交集）

``````if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
path1.op(path2, Path.Op.INTERSECT);//path1与path2进行布尔运算，结果保存至path1
canvas.drawPath(path1,pathPaint);
}

//也可以这样写
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
path3.op(path1,path2,Path.Op.INTERSECT);//path1与path2进行布尔运算，结果保存至path3
canvas.drawPath(path3,pathPaint);
}
``````
##### UNION（并集）

``````if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
path1.op(path2, Path.Op.UNION);//path1与path2进行布尔运算，结果保存至path1
canvas.drawPath(path1,pathPaint);
}

//也可以这样写
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
path3.op(path1,path2,Path.Op.UNION);//path1与path2进行布尔运算，结果保存至path3
canvas.drawPath(path3,pathPaint);
}
``````
##### XOR（异或）

``````if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
path1.op(path2, Path.Op.XOR);//path1与path2进行布尔运算，结果保存至path1
canvas.drawPath(path1,pathPaint);
}

//也可以这样写
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
path3.op(path1,path2,Path.Op.XOR);//path1与path2进行布尔运算，结果保存至path3
canvas.drawPath(path3,pathPaint);
}
``````

#### 2.setLastPoint(float dx, float dy)

Path在调用setLastPoint方法之前执行了某项操作时（绘制直线或曲线等），会将该操作的终点强制设置为(dx,dy)连线（线的曲直取决于该操作本身是绘制直线还是曲线）

``````//用绿线绘制一个矩形
pathPaint.setColor(Color.GREEN);
canvas.drawPath(path,pathPaint);

//强制设置最后一个点为(150,250)，用红线绘制观察变化
path.reset();
path.setLastPoint(150,250);
pathPaint.setColor(Color.RED);
canvas.drawPath(path,pathPaint);
``````
``````//用绿线绘制一个旋转180°的圆弧
pathPaint.setColor(Color.GREEN);
canvas.drawPath(path,pathPaint);

//强制设置最后一个点为(200,200)，用红线绘制观察变化
path.reset();
path.setLastPoint(200,200);
pathPaint.setColor(Color.RED);
canvas.drawPath(path,pathPaint);
``````

### 推荐阅读更多精彩内容

• 本文首发在我的个人博客ghui.me欢迎指教 Path作为Android中一种相对复杂的绘图方式，官方文档中的有些...
ghuizhang阅读 8,011评论 0 11
• 最近项目中要实现加速球效果。是时候该学习一波了，好了废话不多说，记笔记，还是从自己发憷的自定义view开始。 先来...
laifrog阅读 758评论 0 4
• 参考：android绘图之Path总结Path相关方法讲解(一)path类的简化结构图 内部枚举类 构造方法 构造...
蒸汽飞船阅读 2,741评论 0 3
• Paint 属性配置 setAntiAlias：抗锯齿 setDither：抗抖动 setColor,setARG...
简祖明阅读 257评论 0 4
• 参考：https://juejin.im/post/58ce7fe561ff4b006c9a63c6https:/...
zhaoyubetter阅读 3,413评论 0 5