簡體   English   中英

RecyclerView通過itemTouchHelper拖放,拖動時快速拖動

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

我一直在關注這個鏈接的指南“使用RecyclerView拖動和滑動 - 由IPaulPro” ,我在某些情況下遇到的問題很少。

所以,我基本上完成了他解釋的所有內容+我在項目中添加了一個TextView,表示RecyclerView中項目的位置,如下所示: 在此輸入圖像描述

一切都很好看,除非我開始“快速射擊”物品,然后我有兩個問題:

  1. 它碰巧有數字的重復。 在此輸入圖像描述

    此外,我所做的是使用notifyAdapterSetChanged()onItemClear()方法-它固定在它的方式,反而造成IllegalStateException ,其逮住-會導致IndexOutOfBounds例外。

  2. 有時,當刷得太快時,物品進入“背景”。 只有當項目大小不同時才能看到這一點。 在此輸入圖像描述

我將在下面粘貼我的整個適配器代碼,其中必須存在缺陷。

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的問題,但沒有答案,我可能會更幸運。

更改你的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;
}

對我來說,似乎你的onItemMove()沒有考慮到所有的變化。 當某些東西移動多個項目時(比如在A和B之間),您正在交換兩者之間的所有項目。 但是,您只將更改報告給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()並刪除其余的通知代碼。

我知道它已經很晚了,因為我在這里找不到正確的答案。 只需在返回true之前添加notifyItemRangeChanged(fromPosition,toPosition)

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM