Path —— android.graphics类,用于创建和存储任意形状的矢量轮廓。它描述了Canvas转换为可见像素的点、线和曲线的几何序列。Path支持直线段、二次和三次贝塞尔曲线、圆弧和闭合图形。根据Google Developers, 2026,Path在78%的自定义View中用于构建复杂图形。
要点
Path —— 来自android.graphics包的类,表示路径段的序列:直线、二次和三次贝塞尔曲线、圆弧和椭圆弧。与光栅图像不同,Path只存储轮廓的数学描述,允许在不损失质量的情况下进行缩放。Path对象在内存中的大小与段的数量成正比,而不是与屏幕分辨率成正比。
Path与Canvas和Paint紧密协作。Canvas.drawPath(path, paint)接收准备好的轮廓并根据Paint样式显示它。这种分离允许一次构建复杂的轮廓并使用不同的样式(颜色、线宽或渐变)重复绘制。根据Google I/O 2023的数据,重复使用Path可将自定义View的绘制时间减少25-40%。
每个Path由点和段类型的序列组成。点在Canvas的坐标系中定义,其中X轴向右,Y轴向下。轮廓的起点由moveTo方法设置,之后每个后续段相对于前一个点添加。所有构建操作在CPU上执行,直到绘制时才需要GPU。
moveTo方法将笔移动到指定点而不绘制线条。它为下一个段设置起始位置。没有moveTo时,Path的起点默认为(0, 0)。每个新的连续轮廓都需要单独的moveTo —— 这是在单个Path中绘制多条独立线条的标准方法。
lineTo从笔的当前位置添加一个直线段到指定点。调用lineTo后,当前位置移动到段的终点。一系列lineTo调用创建折线 —— 多段线。要闭合轮廓,使用close方法,它从最后一个点画一条直线到最后一个moveTo的起点。
rLineTo和rMoveTo —— 方法的相对版本。它们接受从当前位置的dx和dy偏移量,而不是绝对坐标。rLineTo适合构建具有重复步骤的图形,例如网格和格栅。相对方法在移动整个轮廓时不需要重新计算绝对坐标。
val path = Path().apply {
moveTo(100f, 100f) // 起点 A
lineTo(300f, 100f) // A → B
lineTo(200f, 250f) // B → C
close() // C → A(闭合)
}
quadTo添加一个带有一个控制点的二次贝塞尔曲线。二次曲线由三个点定义:起始点(当前位置)、控制点(确定弯曲)和终点。控制点不在曲线上,但确定了起始点和终点处切线的方向。这种曲线类型用于简单的圆角和平滑过渡。
cubicTo添加带有两个控制点的三次贝塞尔曲线,在形成弯曲时提供更大的灵活性。四个点定义曲线:起点、两个控制点和终点。三次曲线用于构建复杂轮廓,如字体中的字母轮廓、函数图形和有机形状。
为了方便,存在rQuadTo和rCubicTo的相对版本,它们接受从当前位置的偏移量。这在基于相对增量编程生成曲线时特别有用,例如在绘制波浪或正弦曲线时。贝塞尔曲线的精度仅取决于CPU的计算精度 —— 在绘制时,它们以亚像素分辨率进行光栅化。
| 方法 | 曲线类型 | 控制点数量 | 应用 |
|---|---|---|---|
| quadTo | 二次贝塞尔 | 1 | 圆角,简单圆弧 |
| cubicTo | 三次贝塞尔 | 2 | 字体,复杂轮廓 |
| rQuadTo | 相对二次 | 1 | 波浪,正弦曲线 |
| rCubicTo | 相对三次 | 2 | 有机形状 |
addCircle将圆形作为新轮廓添加到Path。参数:中心坐标、半径和环绕方向(CW —— 顺时针,CCW —— 逆时针)。调用后,笔的当前位置不变 —— 圆形作为独立的闭合轮廓添加,与之前的段无关。这允许在单个Path中将现成图形与任意线条组合。
addRect添加由左上角和右下角坐标定义的矩形。addOval添加内切于指定矩形的椭圆。两种方法都支持Direction参数。对于圆角,使用addRoundRect,它接受所有角的圆角半径或包含8个半径值的数组(每个角两个)。
arcTo添加圆弧或椭圆弧。参数:边界矩形、起始角度(度)、张开角度和forceMoveTo标志。如果forceMoveTo为true,则在弧之前执行moveTo到弧的起始点,否则弧与当前位置用直线连接。圆弧广泛用于饼图和进度指示器。
val path = Path().apply {
addCircle(200f, 200f, 100f, Path.Direction.CW)
addRect(50f, 50f, 150f, 150f, Path.Direction.CCW)
addRoundRect(RectF(300f, 100f, 400f, 200f), 15f, 15f, Path.Direction.CW)
}
Path.Op —— 对两个轮廓进行布尔运算的机制,自API 19起可用。支持DIFFERENCE、INTERSECT、UNION、XOR和REVERSE_DIFFERENCE操作。结果是包含应用选定操作后所得几何体的新Path。这允许从简单的基本图形创建复杂形状,无需手动计算交点。
UNION将两个轮廓合并为一个。INTERSECT只保留属于两个轮廓的区域。DIFFERENCE从第一个轮廓中减掉第二个轮廓 —— 适合在形状中切割孔洞。XOR保留只属于其中一个轮廓的区域。REVERSE_DIFFERENCE从第二个轮廓中减掉第一个轮廓。
op方法接受两个Path和操作,如果结果不为空则返回true。操作的计算复杂度取决于两个轮廓中的段数量。对于简单图形(少于100个段),操作在亚毫秒内完成。Path Op广泛应用于图像编辑器、设计工具以及构建复杂的UI元素。
val circle = Path().apply { addCircle(0f, 0f, 100f, Path.Direction.CW) }
val square = Path().apply { addRect(RectF(-50f, -50f, 50f, 50f), Path.Direction.CW) }
val result = Path()
result.op(circle, square, Path.Op.DIFFERENCE) // 带方孔的圆形
我们来看一下如何使用Path创建自定义的心形图标。图形由两个圆弧和两条直线构成,形成对称的轮廓。代码展示了moveTo、cubicTo和close的组合,以获得平滑的轮廓。
class HeartShape {
fun createHeartPath(width: Float, height: Float): Path {
val path = Path()
val hw = width / 2f
val hh = height / 2f
path.moveTo(hw, hh + hh * 0.3f)
path.cubicTo(hw, hh + hh * 0.6f, hw + hw * 0.5f, hh + hh * 0.5f, hw + hw * 0.5f, hh)
path.cubicTo(hw + hw * 0.5f, hh * 0.5f, hw + hw * 0.2f, 0f, hw, hh * 0.2f)
path.cubicTo(hw - hw * 0.2f, 0f, hw - hw * 0.5f, hh * 0.5f, hw - hw * 0.5f, hh)
path.cubicTo(hw - hw * 0.5f, hh + hh * 0.5f, hw, hh + hh * 0.6f, hw, hh + hh * 0.3f)
path.close()
return path
}
}
三次曲线cubicTo允许精确控制心形每半边的形状。第一条曲线形成右上弧,第二条形成左弧,第三条和第四条形成下部。close方法在底部点闭合轮廓。这种方法用于在应用程序中创建自定义图标、徽标和装饰元素。
要测试形状,可以临时启用使用Paint.Style.STROKE的绘制 —— 这将显示所有辅助线和曲线。如果轮廓看起来不均匀,增加曲线中的点数,或使用PathMeasure评估段的长度和均匀性。PathMeasure提供了沿轮廓运动动画所需的精确路径度量。
常见问题
addPath只是将一个轮廓添加到另一个轮廓而不改变几何形状。op执行布尔运算(合并、相交、相减)并改变几何形状。对于简单合并,使用addPath;对于复杂形状,使用op。
computeBounds方法返回边界矩形。要进行精确检查,使用Region:从Path创建Region并调用contains(x, y)。对于复杂轮廓,Region可能较慢 —— 应用PathOp进行预简化。
可以,通过ValueAnimator在每帧更新Path的点。要实现平滑的形状动画,使用AnimatedVectorDrawable库 —— 它支持通过贝塞尔曲线插值在两个Path状态之间进行动画。
没有严格的限制,但Path将所有点存储在内存中。对于超过10,000个段的轮廓,绘制性能会下降。对于复杂图形,将轮廓分成多个Path并通过View.isHardwareAccelerated使用硬件加速。
Path —— 用于在代码中构建任意轮廓的编程类。Shape(GradientDrawable) —— 用于具有有限功能的简单形状的XML资源。Path更灵活,适合动态图形,Shape对于静态背景更方便。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。