Search code examples
androidkotlinandroid-layoutandroid-recyclerviewandroid-animation

How to wait for a RecyclerView animation to finish before resizing it?


I have a RecyclerView within a RelativeLayout which is vertically constrained between two buttons:

    <RelativeLayout
        android:id="@+id/recvPlayersLayout"
        android:layout_width="300dp"
        android:layout_height="0dp"
        android:layout_marginTop="16dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toTopOf="@+id/btnAddPlayer"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btnPremium">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recvPlayers"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            tools:listitem="@layout/recv_players_row" />

    </RelativeLayout>

The RelativeLayout takes up all the space between the two buttons and the RecyclerView is centered vertically.

In my activity the RecyclerView has these properties:

playerRV.itemAnimator = DefaultItemAnimator()
playerRV.layoutManager = LinearLayoutManager(this)

And rows are added and removed using notifyItemInserted() and notifyItemRemoved().

When adding/removing rows the height of the RecyclerView is adjusted before the animation is played. This works as it should when adding rows but obviously not for removing them as the animation is never seen.

I'm able to view the animation by setting a fixed height when removing a row.

val layoutParams1 = binding.recvPlayers.layoutParams
layoutParams1.height = binding.recvPlayers.height
binding.recvPlayers.layoutParams1 = layoutParams

(playerRV.adapter as PlayerRecyclerViewAdapter).notifyItemRemoved(hintList.size)

I then need to revert the height back to wrap_content.

val layoutParams2 = binding.recvPlayers.layoutParams
layoutParams2.height = ViewGroup.LayoutParams.WRAP_CONTENT
binding.recvPlayers.layoutParams = layoutParams2

Is there a way I can delay this until after the animation is complete? Or should I be using a totally different method?

I have also tried using runBlocking but am not sure if I'm doing it correctly. The animation is still not visible.

val layoutParams1 = binding.recvPlayers.layoutParams
layoutParams1.height = binding.recvPlayers.height
binding.recvPlayers.layoutParams = layoutParams1
runBlocking {
    val job = launch {
        (playerRV.adapter as PlayerRecyclerViewAdapter).notifyItemRemoved(hintList.size)
    }
    job.join()
    val layoutParams2 = binding.recvPlayers.layoutParams
    layoutParams2.height = ViewGroup.LayoutParams.WRAP_CONTENT
    binding.recvPlayers.layoutParams = layoutParams2
}

Solution

  • From the documentation, you can override onAnimationFinished which will be called when your animations has ended.