Drag and drop item of recyclerview in android

Sharing is caring!

Item drag and drop of RecylerView is the very cool feature in android. Drag and drop feature is the inbuilt feature of RecylerView. There are many external libraries are available to drag and drop item and swipe item position. But in this tutorial, I am explaining how to implement this awesome feature of RecylerViewwhich is inbuilt in RecylerView?

The very first thing we need to add the RecylerView dependency in our build.gradle file.

 compile 'com.android.support:recyclerview-v7:23.1.0'

Now you need to add this into layout file.

 <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:scrollbars="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

RecylerView provides ItemThouchhelper class to drag and drop. ItemTouchHelper is the best utility that helps to drag and drop item smoothly. It provides many features like swipe item and restricted target to drop an item, awesome animation and much more. For that RecylerView instance should be attached to ItemTouchHelper callback.

Here I want to drag the recycler view item on long pressed, So I will be enabled isLongPressDragEnabled() and disable the swipe feature isItemViewSwipeEnabled().

public class EditItemTouchHelperCallback extends ItemTouchHelper.Callback {

    private final ItemAdapter mAdapter;

    public EditItemTouchHelperCallback(ItemAdapter adapter) {
        mAdapter = adapter;
    }

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

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

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
                          RecyclerView.ViewHolder target) {
        mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return true;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
    }

}

Ok Great 🙂 Now I need three different listeners to handle all request. What are the requests?

1. While clicking on a view item image to start to item drag.

2. A clickable item view should be the selectable background color and after dismissed, it should be unselected.

3. While moving the item and item dismissed in a target area update recyclerView adapter.

So these three listeners are required for action. Let me create three listeners first then after we will see how and where we need to implement those?

public interface OnStartDragListener {

    void onStartDrag(RecyclerView.ViewHolder viewHolder);

}
public interface ItemTouchHelperViewHolder {

    void onItemSelected();

    void onItemClear();
}
public interface ItemTouchHelperAdapter {

    boolean onItemMove(int fromPosition, int toPosition);

    void onItemDismiss(int position);
}

Now all three listeners are ready. Let’s implement all in our custom adapter class.

public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements ItemTouchHelperAdapter {

    private List<ItemModel> mPersonList;
    OnItemClickListener mItemClickListener;
    private static final int TYPE_ITEM = 0;
    private final LayoutInflater mInflater;
    private final OnStartDragListener mDragStartListener;
    private Context mContext;

    public ItemAdapter(Context context, List<ItemModel> list, OnStartDragListener dragListner) {
        this.mPersonList = list;
        this.mInflater = LayoutInflater.from(context);
        mDragStartListener = dragListner;
        mContext = context;

    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {

        if (viewType == TYPE_ITEM) {
            //inflate your layout and pass it to view holder
            View v = mInflater.inflate(R.layout.person_item, viewGroup, false);
            return new VHItem(v );
        }

        throw new RuntimeException("there is no type that matches the type " + viewType + " + make sure your using types correctly");

    }

    @Override
    public int getItemViewType(int position) {
            return TYPE_ITEM;
    }



    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int i) {

        if (viewHolder instanceof VHItem) {

            final VHItem holder= (VHItem)viewHolder;
            ((VHItem) viewHolder).title.setText(mPersonList.get(i).getName());
            Picasso.with(mContext)
                    .load(mPersonList.get(i).getImagePath())
                    .placeholder(R.drawable.ic_profile)
                    .into(((VHItem) viewHolder).imageView);

            ((VHItem) viewHolder).image_menu.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 mPersonList.size();
    }

    public interface OnItemClickListener {
        public void onItemClick(View view, int position);
    }

    public void setOnItemClickListener(final OnItemClickListener mItemClickListener) {
        this.mItemClickListener = mItemClickListener;
    }

    public class VHItem extends RecyclerView.ViewHolder implements View.OnClickListener ,ItemTouchHelperViewHolder{
        public TextView title;
        private ImageView imageView;
        private ImageView image_menu;

        public VHItem(View itemView) {
            super(itemView);
            title = (TextView) itemView.findViewById(R.id.name);
            image_menu = (ImageView) itemView.findViewById(R.id.image_menu);
            imageView = (ImageView) itemView.findViewById(R.id.circle_imageView);
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            if (mItemClickListener != null) {
                mItemClickListener.onItemClick(v, getPosition());
            }
        }

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

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

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

    @Override
    public boolean onItemMove(int fromPosition, int toPosition) {
        //Log.v("", "Log position" + fromPosition + " " + toPosition);
        if (fromPosition < mPersonList.size() && toPosition < mPersonList.size()) {
            if (fromPosition < toPosition) {
                for (int i = fromPosition; i < toPosition; i++) {
                    Collections.swap(mPersonList, i, i + 1);
                }
            } else {
                for (int i = fromPosition; i > toPosition; i--) {
                    Collections.swap(mPersonList, i, i - 1);
                }
            }
            notifyItemMoved(fromPosition, toPosition);
        }
        return true;
    }

    public void updateList(List<ItemModel> list) {
        mPersonList = list;
        notifyDataSetChanged();
    }
}

With our Callback ready, we can create our ItemTouchHelper and call attachToRecyclerView. Here you need implements the OnStartDrag listener and call the startDrag(viewHolder).

public class MainActivity extends AppCompatActivity implements OnStartDragListener{
       List<ItemModel> list = Utility.getListPerson();

        mRecyclerView.setHasFixedSize(true);
        LinearLayoutManager mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);

        ItemAdapter mAdapter = new ItemAdapter(this, list, this);
        ItemTouchHelper.Callback callback =
                new EditItemTouchHelperCallback(mAdapter);
        mItemTouchHelper = new ItemTouchHelper(callback);
        mItemTouchHelper.attachToRecyclerView(mRecyclerView);

        mRecyclerView.setAdapter(mAdapter);
    @Override
    public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
        mItemTouchHelper.startDrag(viewHolder);
    }

Wrapping up: This is a great implementation of ItemTouchHelper. However, it should be clear that a third-party library is not needed for basic drag & drop and swipe-to-dismiss with RecyclerView. RecyclerVew provides the awesome inbuilt feature to handle all this request. If you wondering Kotlin for android then I would be recommended to check all this post of Kotlin Category.

Here is the source code link for drag and drop item recyclerView in android.

Please do subscribe your email to get every newsletter from this blog and if you feel that this post helps you then do not forget to share and comment below.

Keep Happy coding 🙂

4.5 2 votes
Article Rating

Similar Posts

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

10 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Benny

Great tutorial.. thanks

shaifali

hey Thankyou so much for this tutorial but i have a question, how can we do same thing with grid view

Vaibhav

Please grid view arrangement and Store that position after re open , etc

Seshan Suresh

How to add swipe functionality to it??

prashant

where did you define Utility.getListPerson();?

Avinash jha

Hi,
I like your post. But in this post suppose we use number like 1,2,3 and so on instead of image, then if we drag the item , number is not updated.

Free Stuff

You made some respectable points there. I seemed on the internet for the issue and found most people will go along with together with your website.

Jaimin Patel

Thank u very much for this code

Jaimin Patel

how to store same position after relaunch app and removed from
background