android DefaultItemAnimator#animateChange总是使用oldHolder === newHolder调用

rvpgvaaj  于 2023-05-15  发布在  Android
关注(0)|答案(1)|浏览(137)

我正在尝试实现RecyclerView项的自定义更改动画(animateChange)。
我正在努力解决的问题是,animateChange不是用oldHoldernewHolder的两个不同示例调用的,而是用ViewHolder的一个(已经更改的)示例调用的(oldHoldernewHolder都引用它)。不幸的是,这极大地复杂化了我的动画的实现。

提问

如何配置RecyclerView(和其他相关组件,如AdapterItemAnimatorLayoutManager等),使框架调用animateChange与2个ViewHolder示例(一个用于预布局,一个用于后布局)?

我的ItemAnimator

我已经确保canReuseUpdatedViewHolder返回false,根据文档,应该在调用animateChange之前强制创建新的ViewHolder(或者至少我是这样理解的)。

myRecyclerView.itemAnimator = object : DefaultItemAnimator() {
        
        override fun canReuseUpdatedViewHolder(viewHolder: RecyclerView.ViewHolder) = false
        
        override fun animateChange(
            oldHolder: RecyclerView.ViewHolder,
            newHolder: RecyclerView.ViewHolder,
            preLayoutInfo: ItemHolderInfo,
            postLayoutInfo: ItemHolderInfo
        ): Boolean {
        
            // my anim impl here

            // oldHolder === newHolder at time of this method invocation.
            // However I'd like oldHolder to reference View in its pre-layout state.
            // How to achieve this?
        
            return false
        }
        
    }

我的适配器

我已经确保MyAdapter具有“稳定ID”,并且它正确地覆盖了getItemId(int)

myRecyclerView.adapter = MyAdapter() {
        
        init {
            hasStableIds(true)
        }
        
        fun getItemId(position: Int) = ...
        
        ...
    }

我还确保:
1.... Adapter不会覆盖onBindViewHolder的“有效负载”版本,而是非有效负载版本(onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int))。根据some discussions,这也可能会阻止创建新的ViewHolder示例。
1....在数据更新后,通过notifyDataSetChanged通知适配器:

open fun setMyData(myData: List<MyDataType>) {
     this.myData = myData
     notifyDataSetChanged()
 }

1.... Adapter.getItemViewType(Int)在数据更改后保持类型不变。

wribegjk

wribegjk1#

我设法解决了这个问题。
有问题的部分是notifyDataSetChanged的调用:

open fun setMyData(myData: List<MyDataType>) {
    this.myData = myData
    notifyDataSetChanged()
}

行为如下:
1.对于notifyDataSetChangedItemAnimator.animateChange(...)是通过ViewHolder的单个(并且已经更新/后期布局)示例调用的。
1.但是,调用notifyItemRangeChanged而不是notifyDataSetChanged会导致ItemAnimator.animateChange(...)被调用,其中包含2个ViewHolder示例,一个用于预布局(oldHolder),另一个用于后布局(newHolder)。
最后,我使用DiffUtil为每个列表项正确调用相应的notify*方法。

相关问题