RecyclerView drag&当快速拖动时,通过itemTouchHelper删除怪

时间:2016-02-08 15:54:36

标签: android drag-and-drop android-recyclerview

我一直在关注此链接的导游"Drag and Swipe with RecyclerView - by IPaulPro",我在某些情况下遇到的问题很少。

所以,我基本上完成了他解释的所有内容+我在项目中添加了一个TextView,表示RecyclerView中项目的位置,如下所示: enter image description here

一切都很好看,除非我开始"吊索射击"物品很快,然后我有两个问题:

  1. 碰巧有重复的数字。 enter image description here

    我所做的也是使用notifyAdapterSetChanged() onItemClear()方法 - 它以某种方式修复它,但却导致了 被抓住的IllegalStateException会导致 IndexOutOfBounds例外。

  2. 偶尔,当刷过太快时,项目会进入"背景"。只有当项目大小不同时才能看到这一点。 enter image description here

  3. 我将在下面粘贴我的整个适配器代码,其中必须存在缺陷。

    LayoutInflater inflater;
    Context context;
    AndroidEntityQuestionResult androidEntityQuestionResult;
    ArrayList<AndroidEntityAnswer> list = new ArrayList<>();
    ORDLayoutManagerQuestion ord;
    ScreenDimensionsConstants sdc;
    
    
    public OrderingRecycleAdapter(Context context, AndroidEntityQuestionResult androidEntityQuestionResult, ORDLayoutManagerQuestion ord) {
        inflater = LayoutInflater.from(context);
        this.context = context;
        this.list = androidEntityQuestionResult.getAndroidEntityQuestion().getEntityAnswer();
        this.androidEntityQuestionResult = androidEntityQuestionResult;
        this.ord = ord;
        sdc = new ScreenDimensionsConstants(context);
    }
    
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = inflater.inflate(R.layout.custom_row_ordering_rv, parent, false);
        final RecyclerView.ViewHolder holder = new OrderingViewHolder(view);
        return holder;
    }
    
    
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof OrderingViewHolder) {
    
            ((OrderingViewHolder) holder).answerText.setText(list.get(position).getAnswer().getANSWER_TEXT());
            int currentPosition = position + 1;
            ((OrderingViewHolder) holder).position.setText("#" + currentPosition);
        }
    }
    
    @Override
    public int getItemCount() {
        return list.size();
    }
    
    @Override
    public boolean onItemMove(int fromPosition, int toPosition) {
        if (fromPosition < toPosition) {
            for (int i = fromPosition; i < toPosition; i++) {
                Collections.swap(list, i, i + 1);
            }
        } else {
            for (int i = fromPosition; i > toPosition; i--) {
                Collections.swap(list, i, i - 1);
            }
        }
        notifyItemMoved(fromPosition, toPosition);
        notifyItemChanged(fromPosition);
        return true;
    }
    
    @Override
    public void onItemDismiss(int position) {
    
    }
    
    @Override
    public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
            ord.getItemTouchHelper().startDrag(viewHolder);
    }
    
    class OrderingViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder {
        private TextView answerText;
        private ImageView pin;
        private TextView position;
    
        public OrderingViewHolder(View itemView) {
            super(itemView);
            answerText = (TextView) itemView.findViewById(R.id.orderingAnswer);
            answerText.setTextSize(TypedValue.COMPLEX_UNIT_PX, sdc.getHeight() / 40);
    
            pin = (ImageView) itemView.findViewById(R.id.ordering_pin);
            pin.getLayoutParams().width = sdc.getHeight() / 15;
            pin.getLayoutParams().height = sdc.getHeight() / 15;
    
            pin.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (MotionEventCompat.getActionMasked(event) ==
                            MotionEvent.ACTION_DOWN) {
                        OrderingRecycleAdapter.this.onStartDrag(OrderingViewHolder.this);
                    }
                    return false;
                }
            });
            position = (TextView) itemView.findViewById(R.id.answer_position);
            position.setTextSize(TypedValue.COMPLEX_UNIT_PX, sdc.getHeight() / 40);
    
        }
    
        @Override
        public void onItemSelected() {
            itemView.setBackgroundResource(R.drawable.menu_item_background_ice_blue);
        }
    
        @Override
        public void onItemClear() {
            itemView.setBackgroundResource(R.drawable.menu_item_background_white);
            int currentPosition = getLayoutPosition() + 1;
            position.setText("#" + currentPosition);
           //notifyDataSetChanged();
    
        }
    }
    

    奖金问题

    是否有任何教程或任何与2个RecyclerViews之间的拖放相关的信息?

    我知道有关于SO的问题,但没有答案,我可能会更幸运。

3 个答案:

答案 0 :(得分:2)

更改你的onitemmove方法

@Override
public boolean onItemMove(int fromPosition, int toPosition) {
    if (fromPosition < toPosition) {
        for (int i = fromPosition; i < toPosition; i++) {
            Collections.swap(list, i, i + 1);
        }
    } else {
        for (int i = fromPosition; i > toPosition; i--) {
            Collections.swap(list, i, i - 1);
        }
    }
    notifyItemMoved(fromPosition, toPosition);
    notifyItemChanged(fromPosition);
    return true;
}

为:

@Override
public boolean onItemMove(int fromPosition, int toPosition) {
    if (fromPosition < toPosition) {
        for (int i = fromPosition; i < toPosition; i++) {
            Collections.swap(list, i, i + 1);
        }
    } else {
        for (int i = fromPosition; i > toPosition; i--) {
            Collections.swap(list, i, i - 1);
        }
    }
    notifyItemMoved(fromPosition, toPosition);
    return true;
}

答案 1 :(得分:0)

对我来说,似乎你的onItemMove()没有考虑到所有的变化。 当某些东西移动多个项目时(比如A&amp; B之间),您正在交换两者之间的所有项目。 但是,您只向A&amp; A报告更改。 B而不是其间的其他元素。

我建议您编写一个报告所有更改的交换方法:

public boolean swapItems(int fromPosition, int toPosition){
    Collections.swap(list, fromPosition, toPosition);
    notifyItemMoved(fromPosition, toPosition);
    notifyItemMoved(toPosition, fromPosition);
    // And maybe also notifyItemChanged() as the item changes due to the shift
    notifyItemChanged(fromPosition);
    notifyItemChanged(toPosition);
}

调用此函数而不是Collections.swap()并删除其余的通知代码。

答案 2 :(得分:0)

我知道它已经很晚了,因为我无法在这里找到正确的答案。只需在返回true之前添加notifyItemRangeChanged(fromPosition,toPosition)

notifyItemChanged(fromPosition);
notifyItemMoved(fromPosition, toPosition);
notifyItemRangeChanged(fromPosition,toPosition)