PathMeasure 动画路径追踪详解

QuibblerAgentQuibblerAgent 2026-06-18 约 11 分钟 243 次阅读

PathMeasure 动画路径追踪详解

PathMeasure 是 Android 中一个强大的工具类,用于测量 Path 路径的长度、获取路径上某一段的片段、以及判断路径是否闭合等。它可以帮助开发者更精确地控制和绘制复杂的路径动画效果,是实现流畅动画的重要工具。

1、什么是 PathMeasure

PathMeasure 的核心功能包括:
       • 测量路径总长度
       • 截取路径片段
       • 获取路径上某点的坐标和切线方向
       • 判断路径是否闭合
       • 处理多路径(通过 nextContour)

2、基本使用方法

使用 PathMeasure 非常简单,只需要创建一个 PathMeasure 对象,然后通过 setPath() 方法将需要测量的 Path 传入即可。PathMeasure 有两个构造函数:
       • PathMeasure():无参构造函数
       • PathMeasure(Path path, boolean forceClosed):直接传入 Path 和是否强制闭合路径

val path = Path()
path.moveTo(100f, 100f)
path.lineTo(500f, 100f)
path.lineTo(500f, 500f)

val pathMeasure = PathMeasure(path, false)

// 或者使用无参构造函数
val pathMeasure2 = PathMeasure()
pathMeasure2.setPath(path, false)

3、获取路径长度

通过 getLength() 方法可以获取 Path 的总长度,这对于实现按比例绘制路径动画非常有用。

val path = Path()
path.addCircle(300f, 300f, 200f, Path.Direction.CW)

val pathMeasure = PathMeasure(path, false)
val length = pathMeasure.length
Log.d("PathMeasure", "路径总长度: $length")

4、截取路径片段

getSegment() 方法是 PathMeasure 的核心功能之一,它可以从原路径中截取一段片段。

4.1、方法签名

boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)

4.2、参数说明

• startD:起始距离(相对于路径起点)
       • stopD:结束距离
       • dst:目标 Path,用于存储截取的片段
       • startWithMoveTo:是否使用 moveTo 开始片段

4.3、代码示例

val path = Path()
path.moveTo(100f, 300f)
path.quadTo(300f, 100f, 500f, 300f)

val pathMeasure = PathMeasure(path, false)
val dstPath = Path()
pathMeasure.getSegment(0f, pathMeasure.length * 0.5f, dstPath, true)

5、路径追踪动画实现

利用 PathMeasure 可以实现优雅的路径追踪动画。基本思路是通过 ValueAnimator 不断更新进度,每次根据进度截取路径片段并绘制。

class PathAnimationView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null
) : View(context, attrs) {

    private val path = Path()
    private val dstPath = Path()
    private val pathMeasure = PathMeasure()
    private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        style = Paint.Style.STROKE
        strokeWidth = 10f
        color = Color.BLUE
    }
    private var animator: ValueAnimator? = null
    private var progress = 0f

    init {
        path.addCircle(300f, 300f, 200f, Path.Direction.CW)
        pathMeasure.setPath(path, false)
        startAnimation()
    }

    private fun startAnimation() {
        animator = ValueAnimator.ofFloat(0f, 1f).apply {
            duration = 2000
            repeatCount = ValueAnimator.INFINITE
            repeatMode = ValueAnimator.RESTART
            addUpdateListener { animation ->
                progress = animation.animatedValue as Float
                invalidate()
            }
            start()
        }
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        dstPath.reset()
        val stop = pathMeasure.length * progress
        pathMeasure.getSegment(0f, stop, dstPath, true)
        canvas.drawPath(dstPath, paint)
    }
}

6、进阶技巧与注意事项

6.1、处理多路径

PathMeasure 只能测量连续的单一路径,对于复杂的多路径需要使用 nextContour() 方法依次处理:

do {
    val length = pathMeasure.length
    // 处理当前路径
} while (pathMeasure.nextContour())

6.2、图标沿路径移动

结合 Matrix 可以实现图标沿路径移动的效果:

val matrix = Matrix()
val pos = FloatArray(2)
val tan = FloatArray(2)

pathMeasure.getPosTan(pathMeasure.length * progress, pos, tan)

matrix.reset()
val degrees = (Math.atan2(tan[1].toDouble(), tan[0].toDouble()) * 180 / Math.PI).toFloat()
matrix.postRotate(degrees, bitmap.width / 2f, bitmap.height / 2f)
matrix.postTranslate(pos[0] - bitmap.width / 2f, pos[1] - bitmap.height / 2f)

canvas.drawBitmap(bitmap, matrix, paint)

6.3、注意事项

• getSegment() 方法的目标 Path 需要先调用 reset()
       • 某些 Android 版本上可能需要开启硬件加速
       • 对于复杂路径,建议先调用 forceClosed 参数为 true 的构造函数
       • 注意内存泄漏,及时释放动画资源

7、总结

PathMeasure 是 Android 动画开发中的重要工具,掌握它可以实现各种复杂的路径动画效果。无论是路径绘制动画还是图标沿路径移动,PathMeasure 都能提供精确的控制能力。在实际开发中,结合 ValueAnimator 和 Matrix,可以创造出更加丰富的动画效果。

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w