简体   繁体   English

RecyclerView通过itemTouchHelper拖放,拖动时快速拖动

[英]RecyclerView drag & drop via itemTouchHelper bahaving strange when dragging fast

I've been following guide from this link "Drag and Swipe with RecyclerView - by IPaulPro" and i am having few problems on some situations. 我一直在关注这个链接的指南“使用RecyclerView拖动和滑动 - 由IPaulPro” ,我在某些情况下遇到的问题很少。

So, i basically did all that he explained + i added a TextView in item that represents the position of an item in RecyclerView, something like this: 所以,我基本上完成了他解释的所有内容+我在项目中添加了一个TextView,表示RecyclerView中项目的位置,如下所示: 在此输入图像描述

Everything appears nice except when i start "sling shooting" items fast, then i have two problems: 一切都很好看,除非我开始“快速射击”物品,然后我有两个问题:

  1. It happens to have a duplicate of numbers. 它碰巧有数字的重复。 在此输入图像描述

    Also what i did was using notifyAdapterSetChanged() in the onItemClear() method - it fixed it in a way, but caused IllegalStateException , which catched - would lead to IndexOutOfBounds exception. 此外,我所做的是使用notifyAdapterSetChanged()onItemClear()方法-它固定在它的方式,反而造成IllegalStateException ,其逮住-会导致IndexOutOfBounds例外。

  2. Ocasionally,when swiped too fast, item gets in the "background". 有时,当刷得太快时,物品进入“背景”。 This can only be seen if items are not the same size. 只有当项目大小不同时才能看到这一点。 在此输入图像描述

I will paste my whole adapter code below, there must be a flaw somewhere in it. 我将在下面粘贴我的整个适配器代码,其中必须存在缺陷。

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();

    }
}

BONUS QUESTION 奖金问题

Is there any tutorial or any info related to drag and drop between 2 RecyclerViews? 是否有任何教程或任何与2个RecyclerViews之间的拖放相关的信息?

I know that there is a question on SO, but with no answer, i may be luckier here. 我知道有关于SO的问题,但没有答案,我可能会更幸运。

Change your onitemmove method 更改你的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;
}

to: 至:

@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;
}

To me it seems like your onItemMove() does not account for all the changes. 对我来说,似乎你的onItemMove()没有考虑到所有的变化。 When something moves for more than one item (lets say between A & B), you are are swapping all the items between the two. 当某些东西移动多个项目时(比如在A和B之间),您正在交换两者之间的所有项目。 However you report changes only to A & B and not to the rest of the elements in between. 但是,您只将更改报告给A和B,而不报告其间的其他元素。

I suggest you write a swap method that reports all the changes: 我建议你写一个报告所有变化的交换方法:

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);
}

Call this function instead of Collections.swap() and remove the rest of the notify code. 调用此函数而不是Collections.swap()并删除其余的通知代码。

I know its late, Since I can't see the correct answer posting the answer here. 我知道它已经很晚了,因为我在这里找不到正确的答案。 Just add notifyItemRangeChanged(fromPosition,toPosition) before return true. 只需在返回true之前添加notifyItemRangeChanged(fromPosition,toPosition)

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 拖动时如何在使用 ItemTouchHelper 时取消 RecyclerView 中项目的拖动? - How to cancel dragging of items in RecyclerView when using ItemTouchHelper, as you drag? RecyclerView拖放 - 使用ItemTouchHelper - 如何在拖动时更快地设置滚动速度? - RecyclerView drag-drop - using ItemTouchHelper - How to set scrolling speed faster while dragging? 使用 ItemTouchHelper 拖动项目时 RecyclerView 滚动到顶部 - RecyclerView scrolls to top when dragging item with ItemTouchHelper 使用 itemtouchhelper、recyclerview 和 Firestore 拖放项目,例如 Google Tasks - Drag & drop items with itemtouchhelper, recyclerview and Firestore like Google Tasks RecyclerView ItemTouchHelper 动作拖动结束 - RecyclerView ItemTouchHelper Action Drag Ended RecyclerView ItemTouchHelper 动作拖动开始 - RecyclerView ItemTouchHelper Action Drag Started Android CardView拖放ItemTouchHelper - Android CardView Drag and Drop ItemTouchHelper RecyclerView ItemTouchHelper.Callback:拖动交换条件 - RecyclerView ItemTouchHelper.Callback: Dragging swap condition 如何使 RecyclerView 的 ItemTouchHelper 仅在列表的一部分上工作(拖放) - How to make the RecyclerView's ItemTouchHelper work on only part of the list(drag & drop) 如何使用ItemTouchHelper.Callback将项目拖放到水平recyclerview的边界上? - How to drag and drop items over bounds of the horizontal recyclerview with ItemTouchHelper.Callback?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM