将 Android Lottie 动画与滚动对齐
Align Android Lottie animation to scrolling
我想使我的 Lottie 动画进度与 RecyclerView 或 ViewPager 的滚动对齐。然而,Lottie 似乎只显示“真实”的帧,并没有在它们之间进行插值。当正常播放动画时,这不会发生,Lottie 会在帧之间进行插值。如果我滚动得非常慢,我可以看到我的 RecyclerView 滚动但 Lottie 不更新框架。这是我目前所做的:
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val offset = recyclerView.computeHorizontalScrollOffset()
val extent = recyclerView.computeHorizontalScrollExtent()
val range = recyclerView.computeHorizontalScrollRange()
val percentage = offset.toFloat() / (range.toFloat() - extent.toFloat())
lottieAnimationView.progress = percentage
}
}
当我尝试在 ValueAnimator 中更新进度时出现同样的问题,例如:
val valueAnimator = ValueAnimator.ofFloat(0f, 1f)
valueAnimator.duration = 30000
valueAnimator.addUpdateListener { animation ->
lottieAnimationView.progress = animation.animatedFraction
}
valueAnimator.start()
我不确定我是不是漏掉了什么,或者 Lottie 不支持这个。它似乎与 iOS 一起工作。
这是我的问题的示例视频。上面的动画是通过 playAnimation
完成的,下面的动画是通过 valueAnimator
和 setProgress
:
完成的
我正在使用 Lottie 2.7.0,但我也尝试使用旧版本,如 2.6.x。我也尝试了最新的测试版 Lottie 3.0.0-beta4,但也遇到了同样的问题。
该应用尚未迁移到 AndroidX。
更新答案
自版本 3.0.7
起,问题已修复 (GitHub Issue)。现在可以使用 setProgress(float)
并在帧之间进行插值。
旧答案
我最终得到了一个 hacky 解决方法。可以使用 ValueCallback
调整部分动画。如果动画是一个合成(因此它的图层有自己的时间轴),则可以自行调整时间范围。幸运的是,我的动画就是这种情况。
当“根层”被称为“根”时,使用上面的示例会导致以下代码:
val valueCallback = LottieValueCallback(1f)
lottieAnimationView.addValueCallback(KeyPath("root"), LottieProperty.TIME_REMAP, valueCallback)
val valueAnimator = ValueAnimator.ofFloat(0f, 3.14f)
valueAnimator.duration = 30000
valueAnimator.addUpdateListener { animation ->
valueCallback.setValue(animation.animatedValue as Float)
}
valueAnimator.start()
边节点:
- 带有
TIME_REMAP
的ValueCallback
使用了秒的时间值,而不是进度或帧数!
- 动画必须 运行 - 否则
valueCallback.setValue(..)
将没有效果(例如将其放入循环中)
我真心希望有人能提出比这个更好的解决方案!
我想使我的 Lottie 动画进度与 RecyclerView 或 ViewPager 的滚动对齐。然而,Lottie 似乎只显示“真实”的帧,并没有在它们之间进行插值。当正常播放动画时,这不会发生,Lottie 会在帧之间进行插值。如果我滚动得非常慢,我可以看到我的 RecyclerView 滚动但 Lottie 不更新框架。这是我目前所做的:
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val offset = recyclerView.computeHorizontalScrollOffset()
val extent = recyclerView.computeHorizontalScrollExtent()
val range = recyclerView.computeHorizontalScrollRange()
val percentage = offset.toFloat() / (range.toFloat() - extent.toFloat())
lottieAnimationView.progress = percentage
}
}
当我尝试在 ValueAnimator 中更新进度时出现同样的问题,例如:
val valueAnimator = ValueAnimator.ofFloat(0f, 1f)
valueAnimator.duration = 30000
valueAnimator.addUpdateListener { animation ->
lottieAnimationView.progress = animation.animatedFraction
}
valueAnimator.start()
我不确定我是不是漏掉了什么,或者 Lottie 不支持这个。它似乎与 iOS 一起工作。
这是我的问题的示例视频。上面的动画是通过 playAnimation
完成的,下面的动画是通过 valueAnimator
和 setProgress
:
我正在使用 Lottie 2.7.0,但我也尝试使用旧版本,如 2.6.x。我也尝试了最新的测试版 Lottie 3.0.0-beta4,但也遇到了同样的问题。
该应用尚未迁移到 AndroidX。
更新答案
自版本 3.0.7
起,问题已修复 (GitHub Issue)。现在可以使用 setProgress(float)
并在帧之间进行插值。
旧答案
我最终得到了一个 hacky 解决方法。可以使用 ValueCallback
调整部分动画。如果动画是一个合成(因此它的图层有自己的时间轴),则可以自行调整时间范围。幸运的是,我的动画就是这种情况。
当“根层”被称为“根”时,使用上面的示例会导致以下代码:
val valueCallback = LottieValueCallback(1f)
lottieAnimationView.addValueCallback(KeyPath("root"), LottieProperty.TIME_REMAP, valueCallback)
val valueAnimator = ValueAnimator.ofFloat(0f, 3.14f)
valueAnimator.duration = 30000
valueAnimator.addUpdateListener { animation ->
valueCallback.setValue(animation.animatedValue as Float)
}
valueAnimator.start()
边节点:
- 带有
TIME_REMAP
的ValueCallback
使用了秒的时间值,而不是进度或帧数! - 动画必须 运行 - 否则
valueCallback.setValue(..)
将没有效果(例如将其放入循环中)
我真心希望有人能提出比这个更好的解决方案!