如何在 RecyclerView 中使用 AnimatedStateListDrawable

How to use AnimatedStateListDrawable inside a RecyclerView

我正在尝试创建一个 RecyclerView 任务列表,状态为 doneundone,我想在这些状态之间创建一个漂亮的过渡。

所以我创建了一个 animated-selector 来在状态之间进行转换,但是当我在 RecyclerView 中使用它时,转换不起作用,当我在 [=60= 上测试它时] 在 RecyclerView 之外它可以正常工作。

Screen with the RecyclerView

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>

我在适配器项 onClickListener 中切换 Task 的属性 isDone 并将 animated-selector 设置为 [=23] 的 android:src =] 我的 recyclerView 适配器项目:

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)
}

TaskAdapterinit 我调用 notifyDataSetChanged() 当 liveData allTask​​s 改变时,在 TaskViewHolder 绑定我更新AppCompatImageView 选中状态。

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()
    }
}

我认为问题出在我更改 Task 对象的状态时调用的 notifyDataSetChanged(),因为我想象 RecyclerView 突然更新布局并且不显示过渡状态动画,但如果我不调用 notifyDataSetChanged()RecyclerView 将不会更改列表项状态。

如果有人遇到与我相同的情况,请做出回应。

notifyDataSetChanged() 方法文档中:

RecyclerView will attempt to synthesize visible structural change events for adapters that report that they have {@link #hasStableIds() stable IDs} when this method is used. This can help for the purposes of animation and visual object persistence but individual item views will still need to be rebound and relaid out.

所以我将 hasStableIds() 设置为我的 Adapter 并且成功了!

val taskAdapter = TaskAdapter(this, taskViewModel)
taskAdapter.setHasStableIds(true)