RecyclerView,项目滑动,java.lang.IllegalStateException
RecyclerView, item swiping, java.lang.IllegalStateException
我的任务是在 RecyclerView 中实现项目水平项目滑动。多亏了 ViewPager 源代码和其他一些资源,我实际上已经完成了任务,但是有一个场景有问题。
我的 SwipeableRecyclerView(从现在开始的 SRV)扩展了 RecyclerView 并实现了 RecyclerView.OnItemTouchListener 来执行魔法,这确实有效。它还定义了一个自定义接口,SwipeListener,它定义了一些方法,最重要的(对于这个问题)是 'onSwipe(View view, int position, boolean right)'.
我的 activity 提供了 SRV 接口的实现,当检测到滑动并触发侦听器方法时,它会执行以下操作:
- 使用 'view.animate().translationX(translationX)'
以正确的方向将 item/swiped 视图移出屏幕
- 上面启动的动画有一个监听器,在onAnimationEnd中,从Adapter中移除指定位置的item,并调用adapter.notifyItemRemoved(position)
- 结果是视图消失到滑动的一侧,然后回收器删除带有动画的行 - 所有这些实际上都非常好
快速滑动时有时会出现问题,例如第一个动画尚未完成时,我开始滑动另一行。有时,它会创建 'holes' / 没有视图的幻像行;有时,我会遇到以下异常:
java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
并且堆栈跟踪显示 adapter.notifyItemRemoved() 是导致异常的方法。
对于异常问题,事件顺序如下(来自我的调试跟踪):
started for position: 11
started for position: 10
finished for position: 11
removing 11
removed 11
finished position: 10
removing 10
因此,两个结束动画依次启动,当其中一个移除其项目并调用notifyItemRemoved 时,另一个完成并调用移除项目。我不太确定这是怎么发生的,因为所有这一切都发生在主线程上,实际上,但我猜滚动也是在动画帧中完成的,并且由于第二次删除而需要新的计算。
所以,我很为难,我不知道该怎么办。实际上,我认为最简单的事情应该是在动画开始时禁用整个回收器视图的触摸,并且只有在滚动完成后才再次启用它们。不过,我无法禁用 SRV - 我尝试了 setEnabled(false)、clickable 等,但没有任何效果。
有什么帮助吗?
以下是最终对我有用的方法:
- 向 SRV 添加 swipingEnabled 属性;当 false 时,onInterceptTouchEvent 只是调用父实现,有效地禁用项目滑动
在负责处理滑动手势(如删除条目等)的方法中添加此代码:
swipeableRecyclerView.setSwipingEnabled(false);
在创建 SRV 的位置附近添加此代码:
swipeableRecyclerView.setItemAnimator(new DefaultItemAnimator() {
@Override
public void onRemoveFinished(RecyclerView.ViewHolder item) {
swipeableRecyclerView.setSwipingEnabled(true);
}
});
这只是通过实现移除动画完成时调用的方法来扩展默认项目动画制作器。
现在,我的滑动关闭是 'serialized',没有出现异常。
您可以检查 mRecyclerView.getItemAnimator().isRunning()
,比当前答案更容易一些。虽然 true
、MotionEvent
s 不应触发任何删除。
我的任务是在 RecyclerView 中实现项目水平项目滑动。多亏了 ViewPager 源代码和其他一些资源,我实际上已经完成了任务,但是有一个场景有问题。
我的 SwipeableRecyclerView(从现在开始的 SRV)扩展了 RecyclerView 并实现了 RecyclerView.OnItemTouchListener 来执行魔法,这确实有效。它还定义了一个自定义接口,SwipeListener,它定义了一些方法,最重要的(对于这个问题)是 'onSwipe(View view, int position, boolean right)'.
我的 activity 提供了 SRV 接口的实现,当检测到滑动并触发侦听器方法时,它会执行以下操作:
- 使用 'view.animate().translationX(translationX)' 以正确的方向将 item/swiped 视图移出屏幕
- 上面启动的动画有一个监听器,在onAnimationEnd中,从Adapter中移除指定位置的item,并调用adapter.notifyItemRemoved(position)
- 结果是视图消失到滑动的一侧,然后回收器删除带有动画的行 - 所有这些实际上都非常好
快速滑动时有时会出现问题,例如第一个动画尚未完成时,我开始滑动另一行。有时,它会创建 'holes' / 没有视图的幻像行;有时,我会遇到以下异常:
java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
并且堆栈跟踪显示 adapter.notifyItemRemoved() 是导致异常的方法。
对于异常问题,事件顺序如下(来自我的调试跟踪):
started for position: 11
started for position: 10
finished for position: 11
removing 11
removed 11
finished position: 10
removing 10
因此,两个结束动画依次启动,当其中一个移除其项目并调用notifyItemRemoved 时,另一个完成并调用移除项目。我不太确定这是怎么发生的,因为所有这一切都发生在主线程上,实际上,但我猜滚动也是在动画帧中完成的,并且由于第二次删除而需要新的计算。
所以,我很为难,我不知道该怎么办。实际上,我认为最简单的事情应该是在动画开始时禁用整个回收器视图的触摸,并且只有在滚动完成后才再次启用它们。不过,我无法禁用 SRV - 我尝试了 setEnabled(false)、clickable 等,但没有任何效果。
有什么帮助吗?
以下是最终对我有用的方法:
- 向 SRV 添加 swipingEnabled 属性;当 false 时,onInterceptTouchEvent 只是调用父实现,有效地禁用项目滑动
在负责处理滑动手势(如删除条目等)的方法中添加此代码:
swipeableRecyclerView.setSwipingEnabled(false);
在创建 SRV 的位置附近添加此代码:
swipeableRecyclerView.setItemAnimator(new DefaultItemAnimator() { @Override public void onRemoveFinished(RecyclerView.ViewHolder item) { swipeableRecyclerView.setSwipingEnabled(true); } });
这只是通过实现移除动画完成时调用的方法来扩展默认项目动画制作器。
现在,我的滑动关闭是 'serialized',没有出现异常。
您可以检查 mRecyclerView.getItemAnimator().isRunning()
,比当前答案更容易一些。虽然 true
、MotionEvent
s 不应触发任何删除。