Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

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: enter image description here

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. enter image description here

    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.

  2. Ocasionally,when swiped too fast, item gets in the "background". This can only be seen if items are not the same size. enter image description here

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?

I know that there is a question on SO, but with no answer, i may be luckier here.

like image 871
Sekula1991 Avatar asked Feb 08 '16 15:02

Sekula1991


1 Answers

Change your onitemmove method

@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;
}
like image 195
JAAD Avatar answered Oct 01 '22 03:10

JAAD