I am trying to make a RecyclerView of a list of Tasks with done and undone states and I want to create a beautiful transition between those states.
So I created an animated-selector to make the transition between the states, but the transitions is not working when I use it inside the RecyclerView, when I test it on a Button/ImageView outside the RecyclerView it works as it should.
aslv_status.xml
<?xml version="1.0" encoding="utf-8"?>
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/done"
android:drawable="@drawable/ic_done"
android:state_selected="true" />
<item
android:id="@+id/undone"
android:drawable="@drawable/ic_undone" />
<transition
android:drawable="@drawable/avd_done_to_undone"
android:fromId="@id/done"
android:toId="@id/undone" />
<transition
android:drawable="@drawable/avd_undone_to_undone"
android:fromId="@id/undone"
android:toId="@id/done" />
</animated-selector>
I toggle the attribute isDone of the Task in the adapter item onClickListener and seted the animated-selector as the android:src of the AppCompatImageView of my recyclerView adapter item:
item_task.xml
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{() -> viewModel.toggleTaskState(task)}" >
...
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/imageview_status_image"
android:layout_width="35dp"
android:layout_height="35dp"
android:src="@drawable/aslv_status"
.../>
...
TaskViewModel.kt
fun toggleTaskState(task: Task) = viewModelScope.launch {
task.isDone = !task.isDone
taskRepository.updateTask(task)
}
On TaskAdapter on init I call notifyDataSetChanged() when the liveData allTasks change, and on TaskViewHolder binding I updated the AppCompatImageView selected state.
TaskAdapter.kt
private var allTasks = viewModel.allTasks
init {
viewModel.allTasks.observe(lifecycle, {
notifyDataSetChanged()
})
}
...
class TaskViewHolder(private var binding: ItemTaskBinding, private val viewModel: TaskViewModel)
: RecyclerView.ViewHolder(binding.root) {
fun bind(task: Task) {
binding.task = task
binding.viewModel = viewModel
binding.imageviewStatusImage.isSelected = task.isDone
binding.executePendingBindings()
}
}
I think the problem is the notifyDataSetChanged() called when I change the state of the Task object, because I imagine the RecyclerView updates the layout abruptly and doesn't show the transition state animation, but if I don't call the notifyDataSetChanged() the RecyclerView won't change the list items state.
Responding in case someone goes through the same situation as me.
In the
notifyDataSetChanged()method documentation:So I setted
hasStableIds()to myAdapterand it worked!