Android RecyclerView ItemTouchHelper还原滑动和恢复视图持有者

K K*_*K B 47 android swipe android-recyclerview

有没有办法恢复滑动操作并在滑动完成后将视图固定器恢复到其初始位置并onSwipedItemTouchHelper.Callback实例上调用?我得到了RecyclerView,ItemTouchHelper并且ItemTouchHelper.Callback实例完美地协同工作,我只需要恢复滑动动作,而不是在某些情况下删除滑动项目.

Dar*_*usL 101

经过一些随机的戳后,我找到了解决方案.请求notifyItemChanged适配器.这将使刷出的视图动画回到其原始位置.

  • 这似乎工作得很好,谢谢. (3认同)
  • 大部分时间都有效,但有时候这种情况不起作用. (3认同)
  • 我真的不喜欢这个解决方案,因为它不能顺利地返回到原来的位置,而是暴力地...... (3认同)
  • 它有效,但我有一个问题。当我调用 notifyItemChanged 时,它会在视图中产生一个“闪光”。有没有办法跳过这个“闪光”@DariusL? (2认同)
  • 这会为我播放淡入淡出的动画,而不是平移动画。 (2认同)
  • 这可能是一个非常晚的答复。但是我已经尝试了将近 2 天的反弹动画。这是我目前找到的最好的解决方案。 (2认同)

K K*_*K B 22

Google的ItemTouchHelper实施假定每个刷出的项目最终都会从回收站视图中删除,而在某些应用程序中可能不是这种情况.

RecoverAnimation是一个嵌套类,ItemTouchHelper用于管理滑动/拖动项目的触摸动画.虽然名称暗示它只能恢复项目的位置,但它实际上是唯一用于恢复(取消滑动/拖动)替换(移出滑动或替换拖动)项目的类.奇怪的命名.

有一个名为mIsPendingCleanupin 的布尔属性RecoverAnimation,用于ItemTouchHelper确定该项是否正在等待删除.因此ItemTouchHelper,在将RecoverAnimation项目附加到项目后,在成功滑动后设置此属性,并且只要设置了此属性,动画就不会从恢复动画列表中删除.问题是,mIsPendingCleanup将始终为刷出的项目设置,导致RecoverAnimation项目永远不会从动画列表中删除.因此,即使您在成功滑动后恢复了项目的位置,一旦触摸它,它将被发送回刷出位置 - 因为RecoverAnimation将导致动画从最新的滑出位置开始.

遗憾的是,将ItemTouchHelper类源代码复制到支持库中的相同包中,并mIsPendingCleanupRecoverAnimation类中删除该属性.我不确定这是否可以被谷歌接受,我还没有将更新发布到Play商店,看看是否会导致拒绝,但您可能会发现支持库v22.2.1中的类源代码提到修复https://gist.github.com/kukabi/f46e1c0503d2806acbe2.

  • 它的假设即使在今天仍然有效? (5认同)

jim*_*251 19

您应该覆盖onSwiped方法ItemTouchHelper.Callback并刷新该特定项目.

 @Override
 public void onSwiped(RecyclerView.ViewHolder viewHolder,
     int direction) {
     adapter.notifyItemChanged(viewHolder.getAdapterPosition());
 }
Run Code Online (Sandbox Code Playgroud)


小智 15

一个 脏的解决方法此问题的解决方案是通过调用ItemTouchHelper::attachToRecyclerView(RecyclerView)两次重新附加ItemTouchHelper ,然后调用私有方法ItemTouchHelper::destroyCallbacks().destroyCallbacks()删除项目装饰和所有侦听器,但也清除所有RecoverAnimations.

请注意,我们需要先调用itemTouchHelper.attachToRecyclerView(null)才能ItemTouchHelper认为第二次调用itemTouchHelper.attachToRecyclerView(recyclerView)是一个新的回收器视图.

有关详细信息,请查看ItemTouchHelper 此处的源代码.

变通方法示例:

RecyclerView recyclerView = findViewById(R.id.recycler_view);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);

...
// Workaround to reset swiped out views
itemTouchHelper.attachToRecyclerView(null);
itemTouchHelper.attachToRecyclerView(recyclerView);
Run Code Online (Sandbox Code Playgroud)

将其视为一种肮脏的解决方法,因为此方法使用内部的,未记录的实现细节ItemTouchHelper.

更新:

文件ItemTouchHelper::attachToRecyclerView(RecyclerView):

如果TouchHelper已经连接到RecyclerView,它将首先与前一个分离.您可以使用null调用此方法以将其与当前的RecyclerView分离.

并在参数文档中:

要添加此帮助程序的RecyclerView实例,如果要从当前的RecyclerView中删除ItemTouchHelper,则返回null.

所以至少它部分记录在案.

  • 如果我没有结婚,我会嫁给你.谢谢你,这是唯一适合我的解决方案. (2认同)
  • 您的解决方案使行在没有任何动画的情况下取消滑动。根据您的代码,它更容易并避免了一些随notifyItemChanged 附带的样板代码,但它在视觉上并不吸引人。 (2认同)

Car*_*l B 5

LiveData在使用向 a 提供列表的情况下ListAdapter,调用notifyItemChanged不起作用。但是,我发现了一个糟糕的解决方法,其中涉及在回调中将重新附加ItemTouchHelper到回收器视图onSwiped

val recyclerView = someRecyclerViewInYourCode

var itemTouchHelper: ItemTouchHelper? = null

val itemTouchCallback = object : ItemTouchHelper.Callback {
    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction:Int) {
        itemTouchHelper?.attachToRecyclerView(null)
        itemTouchHelper?.attachToRecyclerView(recyclerView)
    }
}

itemTouchHelper = ItemTouchHelper(itemTouchCallback)

itemTouchHelper.attachToRecyclerView(recyclerView)

Run Code Online (Sandbox Code Playgroud)


joe*_*cks 5

使用最新的 anndroidX 软件包,我仍然遇到这个问题,因此我需要稍微调整 @jimmy0251 解决方案以正确重置该项目(他的解决方案仅适用于第一次滑动)。

 override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
                clipAdapter.notifyItemChanged(viewHolder.adapterPosition)
                itemTouchHelper.startSwipe(viewHolder)
            }
Run Code Online (Sandbox Code Playgroud)

请注意,startSwipe()正确重置该项目的恢复动画。

  • 不起作用,视图已恢复,但是当我尝试在另一个元素中滑动时,它开始在重置的元素中滑动。 (3认同)