sagar suri
sagar suri

Reputation: 4731

How to update all the items in ArrayList due to shift in drag and drop of recyclerview

I have a RecyclerView whose layout is a GridLayout of 3 columns. I am using ItemTouchHelper to drag and drop in the GridLayout of the RecyclerView. In my Adapter there is a method onItemMove() which notify me the items which i have moved. It only swaps those items in the ArrayList which I have dragged and dropped. But due to the drag and drop there is a shift in other elements as well. I want to update their positions as well in the ArrayList.

Here is the Adapter of my Recyclerview:

public class GridAdapter extends RecyclerView.Adapter<GridAdapter.MyViewHolder> implements com.sagar.quizdemo.helper.ItemTouchHelperAdapter {
    String[] str = {"Level 1", "Level 2", "Level 3", "Level 4", "Level 5", "Level 6", "Level 7", "Level 8", "Level 9"};
    List<String> itemList, actualList;
    LayoutInflater inflater;
    Context context;
    private final OnStartDragListener mDragStartListener;

    public GridAdapter(Context context, OnStartDragListener dragStartListener) {
        this.context = context;
        mDragStartListener = dragStartListener;
        inflater = LayoutInflater.from(context);
        itemList = new ArrayList<>();
        actualList = new ArrayList<>(Arrays.asList(str));
    }

    public void getItemList(List<String> nameList) {
        int currentSize = itemList.size();
        itemList.clear();
        itemList.addAll(nameList);
        notifyItemRangeRemoved(0, currentSize);
        notifyItemRangeInserted(0, nameList.size());
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = inflater.inflate(R.layout.custom_level_row, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, int position) {
        holder.textView.setText(itemList.get(position));
        // Start a drag whenever the handle view it touched
        holder.cardView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
                    mDragStartListener.onStartDrag(holder);
                }
                return false;
            }
        });
    }

    @Override
    public int getItemCount() {
        return itemList.size();
    }

    @Override
    public boolean onItemMove(int fromPosition, int toPosition) {
        Collections.swap(itemList, fromPosition, toPosition);
        notifyItemMoved(fromPosition, toPosition);
        notifyItemChanged(fromPosition);
        notifyItemChanged(toPosition);
        return true;
    }

    @Override
    public void onItemDismiss(int position) {
        itemList.remove(position);
        notifyItemRemoved(position);
    }

    public class MyViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder {

        CardView cardView;
        TextView textView;

        public MyViewHolder(View itemView) {
            super(itemView);
            cardView = (CardView) itemView.findViewById(R.id.gameCard);
            textView = (TextView) itemView.findViewById(R.id.gameText);
        }

        @Override
        public void onItemSelected() {
            itemView.setBackgroundColor(Color.LTGRAY);
        }

        @Override
        public void onItemClear() {
            itemView.setBackgroundColor(Color.WHITE);
        }
    }
}

if initially the list is :

{"Level 1", "Level 2", "Level 3", "Level 4", "Level 5", "Level 6", "Level 7", "Level 8", "Level 9"}

After I swap 2nd and 4th positioned elements in the RecyclerView. The updated list should look like this (which I want):

{"Level 1", "Level 5", "Level 2", "Level 3", "Level 4", "Level 6", "Level 7", "Level 8", "Level 9"}

But I am getting this updated list:

{"Level 1", "Level 5", "Level 3", "Level 4", "Level 2", "Level 6", "Level 7", "Level 8", "Level 9"}

Upvotes: 4

Views: 3146

Answers (4)

Do Xuan Nguyen
Do Xuan Nguyen

Reputation: 199

Code here working for me.

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

Upvotes: 2

Zeeshan Sardar
Zeeshan Sardar

Reputation: 235

Try calling notifyDataSetChanged() in onItemMove menthod.

@Override
    public boolean onItemMove(int fromPosition, int toPosition) {
        notifyItemMoved(fromPosition, toPosition);
        notifyItemChanged(fromPosition);
        notifyItemChanged(toPosition);
        notifyDataSetChanged();    
        return true;
    }

Upvotes: 1

Bruke
Bruke

Reputation: 81

Try this instead. In your case, you will first have to find the index of the item to be replaced (fromPosition) and then add toPosition to that index. How to move specific item in array list to the first item

Upvotes: 0

MeliX
MeliX

Reputation: 240

I believe that your problem is that you use Collections.swap(itemList, fromPosition, toPosition);, which swaps objects on the specified positions. So the output is correct. What you need, though:

String item = itemList.remove(fromPostion);
itemList.insert(item, toPosition);

Upvotes: 6

Related Questions