简体   繁体   中英

Align Android Lottie animation to scrolling

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, eg:

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 :

破碎的抽奖动画

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:

  • The ValueCallback with a TIME_REMAP uses a time value in seconds , not a progress or frame number!
  • The animation must run - otherwise valueCallback.setValue(..) will have no effect (eg put it in a loop)

I seriously hope someone will come up with a better solution than this one!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM