# Android知识总结——Path的绘制

## 常用API解析与示例

### 一、xxxTo方法

Path类中提供了一套 xxxTo

。方法汇总如下表所示

lineTo(float x, float y) 绘制直线
x：

moveTo(float x, float y) 移动画笔
x：

arcTo(RectF oval, float startAngle, float sweepAngle) 绘制圆弧
oval：

arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo) 绘制圆弧
oval：

arcTo(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean forceMoveTo) 绘制圆弧
left、top、right、bottom

quadTo(float x1, float y1, float x2, float y2) 绘制二阶贝塞尔曲线

cubicTo(float x1, float y1, float x2, float y2,float x3, float y3) 绘制三阶贝塞尔曲线
，其中 控制点1

#### 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)

（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)

false
，则用法和 arcTo(RectF oval, float startAngle, float sweepAngle)

。若为 true
，先强制调用moveTo 移动path画笔至圆弧起点
，再绘制圆弧。 ps：

，则 forceMoveTo

false

```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)

，向 终点(x₂,y₂)

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

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

，以 (x2,y2)为控制点2
，向 终点(x3,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

，即 相对

，区别在于 rXxxTo方法

，即 相对于path画笔位置

。例如，我们使用 xxxTo

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

，那么如果用 rXxxTo

，即终点设为 (200,200)
，如下所示

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

。所谓 添加

，然后再绘制线，也就是说添加的这段线， 与之前绘制的Path是分离的（除非后绘制的这段线的起始点与之前Path的终点一致）
。方法汇总如下表所示

(RectF oval, float startAngle, float sweepAngle)

oval：

(float left, float top, float right, float bottom, float startAngle,float sweepAngle)

left、top、right、bottom

(float x, float y, float radius, Direction dir)

x：

(RectF oval, Direction dir)

oval：

(float left, float top, float right, float bottom, Direction dir)

left、top、right、bottom

(RectF rect, Direction dir)

rect：

(float left, float top, float right, float bottom, Direction dir)

left、top、right、bottom

(RectF rect, float rx, float ry, Direction dir)

rect：

(float left, float top, float right, float bottom, float rx, float ry,Direction dir)

left、top、right、bottom

(RectF rect, float[] radii, Direction dir)

rect：

(float left, float top, float right, float bottom, float[] radii,Direction dir)

left、top、right、bottom

(Path src)

src：

(Path src, float dx, float dy)

src：

(Path src, Matrix matrix)

src：

3×3的矩阵

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

addArc两个方法使用起来与 arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)
forceMoveTo设置为true

#### 2.addCircle(float x, float y, float radius, Direction dir)

，绘制 起始角度为0°（x轴方向）
，绘制方向通过 dir

CW

CCW

CCW

```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);```

#### 3.addOval(RectF oval, Direction dir)

oval矩形区域

，绘制 起始角度为0°（x轴方向）
，绘制方向通过 dir

CW

CCW

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);```

#### 4.addRect(RectF rect, Direction dir)

，绘制 起点为左上角
，绘制方向通过 dir

CW

CCW

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)

，四个角的 圆角大小一致
，圆角的 横轴半径为rx

dir
CW

dir
CCW

（注意对比顺时针和逆时针的 绘制起点

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);```

#### addRoundRect(RectF rect, float[] radii, Direction dir)

dir
CW

dir
CCW

（注意对比顺时针和逆时针的 绘制起点

，系统会抛出错误信息 radii[] needs 8 values
，如下图所示

addRoundRect(RectF rect, float[] radii, Direction dir)和 addRoundRect(float left, float top, float right, float bottom, float[] radii,Direction dir)

```RectF rectF = new RectF(100,100,400,350);
float[] radii = {60,30,30,70,100,100,10,40};
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);```

Path副本

```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副本
，然后将其进行 平移
x轴

y轴

```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, Matrix matrix)

Path副本
，然后将其进行 矩阵变换
，矩阵为 matrix
（3×3的矩阵）

```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)

ft：

INVERSE_EVEN_ODD
WINDING
INVERSE_WINDING

getFillType
()

isInverseFillType
()

toggleInverseFillType
()

### 五、其他方法

close
()

，连接 起点

reset
()

，保留 填充模式设置
，不保留 Path上相关的数据结构
rewind
()

，不保留 填充模式设置
，但会 保留Path上相关的数据结构
，以便高效地 复用
set
(Path src)

op
(Path path, Op op)

op：

REVERSE_DIFFERENCE（差集）
INTERSECT（交集）
UNION（并集）
XOR（异或）

offset
(float dx, float dy)

x轴

y轴

offset
(float dx, float dy, Path dst)

x轴

y轴

transform
(Matrix matrix)

，矩阵为 matrix
（3×3矩阵）
transform
(Matrix matrix, Path dst)

，矩阵为 matrix
（3×3矩阵）
setLastPoint
(float dx, float dy)

，设置 当前Path最后一个点

isEmpty
()

isConvex
()

。ps：此方法在 API 21

isRect
(RectF rect)

，如是，则 将当前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（差集）

，则运算结果是 path1减去与path2的交集后剩下的部分
，即 path1与path2的并集减去path2部分

```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（差集）

，则运算结果是 path2减去与path1的交集后剩下的部分
，即 path1与path2的并集减去path1部分

```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（交集）

，则运算结果是 path1与path2的交集

```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（并集）

，则运算结果是 path1与path2的并集

```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（异或）

，则运算结果是 path1与path2的并集减去path1与path2的交集

```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

，会将该操作的 终点强制设置为(dx,dy)

setLastPoint

。下面我们通过 封闭图形（矩形）

```//用绿线绘制一个矩形
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);```

|