Facing issue in Position value during Drag and dro

2020-07-24 07:14发布

问题:

How do i get new position value during drag and drop in RecyclerView adapter?

Drag and Drop is working perfect but when i set setOnClickListener to open my detail activity. it gives me the old position value.

For example :

If i drag 2nd item (INDEX 1) and drop at 1st item's position (INDEX 0).

On debuging inside setOnClickListener when i am calling Intent. Position value is 1 (INDEX 1) but what i need is value 0 (INDEX 0).

 @Override
public void onBindViewHolder(final ItemViewHolder holder, final int position) {
    holder.textView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(activity, DetailActivity.class);
                intent.putExtra("NAME_POSITION", position);
                intent.putParcelableArrayListExtra("NAME_LIST", mName);
                ((Activity) context).startActivityForResult(intent, 800);
        }
 }
  • For Drag and drop i have created 2 Classes.

    1) CustomItemTouchHelper extends ItemTouchHelper.Callback

class

//Interface interface

public ItemTouchHelper(Interface interface) {
    this.interface = interface;
}

@Override
public boolean isLongPressDragEnabled() {
    return true;
}

@Override
public boolean isItemViewSwipeEnabled() {
    return false; // swiped disabled
}

@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; // movements drag
    return makeFlag(ItemTouchHelper.ACTION_STATE_DRAG, dragFlags); // as parameter, action drag and flags drag
}

@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
    interface.onMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); // information to the interface
    return true;
}

@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
    // swiped disabled
}    

2) interface for OnMove method

void onMove(int oldPosition, int newPosition);

Implemented this method in activity

    ItemTouchHelper.Callback callback = new CustomItemTouchHelper(this);
    ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
    touchHelper.attachToRecyclerView(list);

interface implemented in activity.

onMove(int oldPosition, int newPosition) {
  Collections.swap(mNames, oldPosition, newPosition);
  adapter.notifyItemMoved(oldPosition, newPosition);
}
  • CORRECT or GUIDE me if some thing is missing.
  • Thanks & Regards.

回答1:

Make sure you override getItemId() method that returns unique value on your adapter.



回答2:

When using drag&drop with recyclerView, the positions get mixed up. Then, whenever you do something where you pass the position (such as an animation for example), the wrong item gets the desired action.

To get the actual current position of the item, add a method in your adapter:

private int getItemPosition(Item item){ // (<-- replace with your item)
    int i = 0;
    // (replace with your items and methods here)
    for (Item currentItem : mItems) {
        if (currentItem.getItemId() == item.getItemId()) break;
        i++;
    }
    return i;
}

and then call this instead to get the position.



回答3:

I had this exact same issue. The problem is that after dragging, "position" passed to onBindViewHolder will change, but onBindViewHolder is never called again so we can't depend on it inside the onClick method. In onBindViewHolder, instead of:

intent.putExtra("NAME_POSITION", position);

use this:

@Override
public void onBindViewHolder(final ItemViewHolder holder, final int position) {

    final Object listItem = list.get(position);

    holder.textView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(activity, DetailActivity.class);
            intent.putExtra("NAME_POSITION", list.indexOf(item);
            intent.putParcelableArrayListExtra("NAME_LIST", mName);
            ((Activity) context).startActivityForResult(intent, 800);
        }
 }

Side note, but you'll also want to change your Collections.swap code. It will mess up the order if you quickly drag over multiple spots. Use this instead:

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