question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Animation does not play when startAnimation is called in onBindViewHolder of an existing view

See original GitHub issue

Describe the bug When calling startAnimation in a RecyclerView’s onBindViewHolder, the animation does not play. This issue was partially fixed in https://github.com/airbnb/lottie-android/issues/1324, but that fix only handles the case when the LottieAnimationView is first created, and not when it is rebound with different data.

The cause of the issue appears to be that when onBindViewHolder is called, the view is in an unusual state where it is attached to the window, but isShown is false because it has no parent.

Steps To Reproduce Here is a unit test that demonstrates the issue:

diff --git a/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/FragmentVisibilityTests.kt b/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/FragmentVisibilityTests.kt
index fc338b93..c48c684d 100644
--- a/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/FragmentVisibilityTests.kt
+++ b/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/FragmentVisibilityTests.kt
@@ -195,6 +195,51 @@ class FragmentVisibilityTests {
         onView(withId(R.id.animation_view)).check(matches(isAnimating()))
     }
 
+    @Test
+    fun testRecyclerViewCanAutoPlayInOnBindRebind() {
+        class TestFragment : Fragment() {
+            override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+                return RecyclerView(requireContext()).apply {
+                    layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
+                    // Setting itemAnimator to null is important for this test in order to
+                    // prevent the recyclerview from creating an additional viewholder for the
+                    // purposes of animation.
+                    itemAnimator = null
+                    adapter = object : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
+                        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+                            return object : RecyclerView.ViewHolder(LottieAnimationView(parent.context).apply {
+                                id = R.id.animation_view
+                                setAnimation(R.raw.heart)
+                                IdlingRegistry.getInstance().register(LottieIdlingResource(this))
+                            }) {}
+                        }
+
+                        override fun getItemCount(): Int = 1
+
+                        override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+                            (holder.itemView as LottieAnimationView).apply {
+                                // Cancel first, then play. This prevents the animation from
+                                // carrying over from the initial binding.
+                                cancelAnimation()
+                                playAnimation()
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        val fragmentScenario = launchFragmentInContainer<TestFragment>()
+        // I wasn't able to figure out exactly what was needed to create an idling resource.
+        // Waiting for [RecyclerView.doOnLayout] was insufficient.
+        Thread.sleep(500)
+        fragmentScenario.onFragment { fragment ->
+            (fragment.view as RecyclerView).adapter!!.notifyItemChanged(0)
+        }
+        Thread.sleep(500)
+        onView(withId(R.id.animation_view)).check(matches(isAnimating()))
+    }
+
     @Test
     fun testDoesntAutoplay() {
         class TestFragment : Fragment() {

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:10

github_iconTop GitHub Comments

3reactions
oissaqcommented, Apr 9, 2020

I’m having the same issue described here and in #1284 My workaround for now is to use post { icon.playAnimation() } That seems to work but wondering if there’s a better solution.

1reaction
gpealcommented, Jan 14, 2022

I re-checked the test in the description (thank you for that) after landing https://github.com/airbnb/lottie-android/pull/1981 and the test now passes!

Read more comments on GitHub >

github_iconTop Results From Across the Web

android - How to animate RecyclerView items when adapter is ...
I am implementing the same thing but when i apply your answer or the accepted answer it doesnt work for me. for initial...
Read more >
RecyclerView.ItemAnimator - Android Developers
This class defines the animations that take place on items as changes are made to the adapter. Subclasses of ItemAnimator can be used...
Read more >
[Android Tips] 33. Lottie 在RecyclerView onBindViewHolder ...
Animation does not play when startAnimation is called in onBindViewHolder of an existing view · Regression: Animation does not play when ...
Read more >
Intermediate RecyclerView Tutorial with Kotlin
In this RecyclerView tutorial you will learn how to build out intermediate techniques like swiping, animation and filtering in Kotlin.
Read more >
Mastering Complex Lists with the Android RecyclerView
The idea of view recycling has been in Android since version 1 in the ... of the RecyclerView don't forget to add the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found