2015-02-11 72 views
3

我的任务是在RecyclerView中实现物品水平物品刷卡。我实际上完成了这项任务,这要归功于ViewPager源代码和其他一些资源,但在一种情况下会遇到问题。RecyclerView,物品刷卡,java.lang.IllegalStateException

我SwipeableRecyclerView(从现在起SRV)扩展RecyclerView并实现RecyclerView.OnItemTouchListener执行的魔力,它的实际工作。它还定义了一个自定义接口SwipeListener,它定义了几个方法,对于这个问题最重要的是'onSwipe(View view,int position,boolean right)'。

我的活动提供界面到SRV的实现,并且当检测到扫动和听者方法烧制,它执行以下操作:

  • 移动项目/在刷卡视图关闭屏幕正确的方向与'view.animate()。translationX(translationX)'
  • 动画开始上面有一个监听器,它在onAnimationEnd,从适配器中删除指定位置的项目,并调用adapter.notifyItemRemoved(位置)
  • 结果是该视图消失到了滑动的一面,然后回收站删除与它的动画行 - 所有这些工作非常好

有时出现问题时,我很快刷卡,因为在第一个动画尚未完成时,我开始刷另一行。有时,它会创建没有视图的'洞'/幻像行;有时候,我得到以下异常:

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),可点击等,但没有任何工作。

任何帮助?

回答

2

下面是最终为我工作:

  • 一个swipingEnabled属性添加到SRV;当假,onInterceptTouchEvent只是调用通过对父类的实现,有效地禁用物品刷卡
  • 中负责处理滑动手势(比如删除该条目等方法添加以下代码):

    swipeableRecyclerView.setSwipingEnabled(false); 
    
  • 添加创建SRV其中接近这个代码:

    swipeableRecyclerView.setItemAnimator(new DefaultItemAnimator() { 
    
        @Override 
        public void onRemoveFinished(RecyclerView.ViewHolder item) { 
         swipeableRecyclerView.setSwipingEnabled(true); 
        } 
    }); 
    

    这只是扩展了默认项动画师与当删除动画完成被称为方法的实现。

现在,我的滑动到解散是'序列化',并没有发生任何异常。

+2

我发现使用onMoveFinished更好,因为这将考虑到物品被删除后的洗牌。 – Ljdawson 2015-04-14 14:45:36

+0

这是否意味着,在onRemoveFinished()完成后,会执行一大堆动作?我假设(也许是错误的),删除包含整个操作... – wujek 2015-04-14 18:00:35

+1

我测试它,它确实是这样的:在onRemoveFinished后,有一大堆onMoveFinished调用。谢谢你的提示。 – wujek 2015-04-18 22:16:07

3

您可以检查mRecyclerView.getItemAnimator().isRunning(),比当前答案容易一点。虽然true,MotionEvent s不应该引发任何删除。

+0

我测试过了,它不起作用。我仍然可以滑动两个或更多视图,以便它们的动画重叠,并导致崩溃。同意,在我的其他代码中可能会出现问题,我会进行更多的测试。不过,谢谢你的发帖,但我并不知道你提到的方法,还有它的姐姐,它会带着一个听众 - 很酷的东西。 – wujek 2015-04-13 18:31:27

+0

可能,这对我有用。动画似乎由adapter.notifyItemRemoved()触发。 – natario 2015-04-13 19:21:42

+0

我明白为什么它不适用于我:当我检测到解雇,在我的解决方案(代理标志),我立即禁用任何其他刷卡并开始完成动画,其onAnimationEnd侦听器方法删除项目并调用notifyItemRemoved() ,导致删除动画开始。您提出的解决方案引入了一个非常短的窗口(从我的滑动结束动画开始运行到notifyItemRemoved()方法被调用时,开始动画)。 (在另一评论中继续)。 – wujek 2015-04-13 20:30:59