【问题标题】:RecyclerView ItemAnimator change order of moving items in default animationRecyclerView ItemAnimator 更改默认动画中移动项目的顺序
【发布时间】:2023-02-17 23:55:24
【问题描述】:

我有一个 recyclerview,它加载了一张卡片列表,每张卡片都有一个最喜欢的按钮。当用户触摸该按钮时,我将列表项设置的顺序更改为首先放置新的收藏卡。该更改在调用 NotifyItemMoved 时显示默认动画,但我想在前面显示向上移动的项目。默认动画显示正在移动到 botton 的项目在其余项目的前面。

搜索了一下,我发现我可以实现一个自定义的 ItemAnimator 并使用这样的东西:

override fun animateMove(
        holder: RecyclerView.ViewHolder?,
        fromX: Int,
        fromY: Int,
        toX: Int,
        toY: Int
    ): Boolean {
        if ( fromY > toY) {
            holder?.itemView?.bringToFront()
        }

        return super.animateMove(holder, fromX, fromY, toX, toY)
    }

看起来效果很好,但是当我滚动列表时它崩溃并出现此错误:java.lang.RuntimeException: trying to unhide a view that was not hiddenandroidx.constraintlayout.widget.ConstraintLayout 如果我删除holder?.itemView?.bringToFront(),默认动画会再次正常运行而不会发生任何崩溃

【问题讨论】:

    标签: android kotlin android-recyclerview


    【解决方案1】:

    您收到“试图取消隐藏未隐藏的视图”错误的原因是视图的 bringToFront() 方法会干扰 RecyclerView 的内部视图回收机制。当视图被回收时,它会被隐藏并重新用于列表中的另一个项目。通过在视图上调用 bringToFront(),您可能会干扰此过程并导致视图被错误地重新用于不同的项目。

    避免此问题的一种方法是创建一个自定义 RecyclerView.ItemAnimator,它覆盖 animateChange() 方法以将移动的视图带到前面,但不会干扰视图回收过程。这是一个示例实现:

    class CustomItemAnimator : DefaultItemAnimator() {
    
        override fun animateChange(
            oldHolder: RecyclerView.ViewHolder?,
            newHolder: RecyclerView.ViewHolder?,
            preInfo: ItemHolderInfo?,
            postInfo: ItemHolderInfo?
        ): Boolean {
            if (oldHolder != null && newHolder != null) {
                // Check if the item is being moved up (i.e. to a lower index)
                if (oldHolder.adapterPosition > newHolder.adapterPosition) {
                    // Bring the new holder's item view to the front
                    newHolder.itemView.bringToFront()
                }
            }
    
            return super.animateChange(oldHolder, newHolder, preInfo, postInfo)
        }
    }
    

    此实现仅在项目向上移动(即,到较低的索引)时将新持有者的项目视图带到前面。这应该允许默认的 RecyclerView 视图回收机制正常工作。

    要使用此自定义 ItemAnimator,请使用 setItemAnimator() 方法将其设置在 RecyclerView 上:

    recyclerView.setItemAnimator(CustomItemAnimator())
    

    注意:此实现假定 RecyclerView 中的每个项目都由 ViewHolder 中的单个视图表示。如果您有包含多个视图的复杂项目布局,您可能需要修改此实现以确保只有项目视图显示在最前面。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多