简体   繁体   中英

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"}

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

Try calling notifyDataSetChanged() in onItemMove menthod.

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

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM