Reputation: 2556
I want to align my Lottie animation progress with the scrolling of a RecyclerView or ViewPager. However Lottie seems to only show the "real" Frames and doesn't interpolate between them. When normally playing the animation this doesn't happen and Lottie interpolates between Frames. If I scroll really slowly I can see that my RecyclerView scrolls but Lottie doesn't update frames. Here is what I currently do:
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
}
}
The same problem occurs when I try to update the progress within a ValueAnimator, e.g.:
val valueAnimator = ValueAnimator.ofFloat(0f, 1f)
valueAnimator.duration = 30000
valueAnimator.addUpdateListener { animation ->
lottieAnimationView.progress = animation.animatedFraction
}
valueAnimator.start()
I'm not sure if I miss something or this isn't supported by Lottie. It seems to work with iOS though.
Here is a sample video of my problem. The top animation is just done via playAnimation
, the lower one is done via valueAnimator
and setProgress
:
I am using Lottie 2.7.0, but I tried using older versions like 2.6.x as well. I tried on the latest beta version, Lottie 3.0.0-beta4, as well, but had the same issue there, too.
The app is not migrated to AndroidX yet.
Upvotes: 1
Views: 2362
Reputation: 2556
Updated answer
The issue is fixed (GitHub Issue) since version 3.0.7
. It's now possible to use setProgress(float)
and it interpolates between frames.
Old answer
I've ended up with a hacky workaround. It's possible to adjust parts of the animation with a ValueCallback
. If the animation is a Composition (so its layers have their own timelines) it's possible to adjust the timeframe itself. Luckily that's the case for my animation.
Using my example from above this leads to the following code, when the "Root-Layer" is called "root":
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()
Sidenodes:
ValueCallback
with a TIME_REMAP
uses a time value in seconds, not a progress or frame number!valueCallback.setValue(..)
will have no effect (e.g. put it in a loop)I seriously hope someone will come up with a better solution than this one!
Upvotes: 1