Tutorial

Android RecyclerView Drag and Drop

Published on August 3, 2022
author

Anupam Chugh

Android RecyclerView Drag and Drop

In this tutorial, we’ll be discussing and implementing the Drag and Drop functionality over our RecyclerView in an Android Application. We’ve already discussed Swipe to Dismiss feature in our previous tutorial.

RecyclerView Drag and Drop

Drag and Drop can be added in a RecyclerView using the ItemTouchHelper utility class. Following are the important methods in the ItemTouchHelper.Callback interface which needs to be implemented:

  • isLongPressDragEnabled - return true here to enable long press on the RecyclerView rows for drag and drop.
  • isItemViewSwipeEnabled - This is used to enable or disable swipes. In this tutorial, we’ll disable this.
  • getMovementFlags - Here we pass the flags for the directions of drag and swipe. Since swipe is disable we pass 0 for it.
  • onMove - Here we set the code for the drag and drop. onSwipe - Here we implement the code for swiping. We’ll keep this empty in the current tutorial.
  • onSelectedChanged - Based on the current state of the RecyclerView and whether it’s pressed or swiped, this method gets triggered. Here we can customize the RecyclerView row. For example, changing the background color.
  • clearView - This method gets triggered when the user interaction stops with the RecyclerView row.

Let’s start building our android application with the drag and drop feature on the RecyclerView.

Project Structure

android drag drop recyclerview

Code

The code for the activity_main.xml layout which contains a RecyclerView only is given below:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layoutManager="android.support.v7.widget.LinearLayoutManager" />


</LinearLayout>

The code for the MainActivity.java is given below:

package com.journaldev.androidrecyclerviewdraganddrop;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    RecyclerView recyclerView;
    RecyclerViewAdapter mAdapter;
    ArrayList<String> stringArrayList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = findViewById(R.id.recyclerView);

        populateRecyclerView();
    }

    private void populateRecyclerView() {
        stringArrayList.add("Item 1");
        stringArrayList.add("Item 2");
        stringArrayList.add("Item 3");
        stringArrayList.add("Item 4");
        stringArrayList.add("Item 5");
        stringArrayList.add("Item 6");
        stringArrayList.add("Item 7");
        stringArrayList.add("Item 8");
        stringArrayList.add("Item 9");
        stringArrayList.add("Item 10");

        mAdapter = new RecyclerViewAdapter(stringArrayList);

        ItemTouchHelper.Callback callback =
                new ItemMoveCallback(mAdapter);
        ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
        touchHelper.attachToRecyclerView(recyclerView);

        recyclerView.setAdapter(mAdapter);
    }

}

In this, we’ve populated a RecyclerViewAdapter.java class with an ArrayList of Strings. We’ve attached an instance of the ItemMoveCallback.java class on the RecyclerView to start drag and drop. Let’s look at each of these files. The code for the ItemMoveCallback.java class is given below:

package com.journaldev.androidrecyclerviewdraganddrop;

import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;

public class ItemMoveCallback extends ItemTouchHelper.Callback {

    private final ItemTouchHelperContract mAdapter;

    public ItemMoveCallback(ItemTouchHelperContract adapter) {
        mAdapter = adapter;
    }

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

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



    @Override
    public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int i) {

    }

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

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

    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder,
                                  int actionState) {


        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
            if (viewHolder instanceof RecyclerViewAdapter.MyViewHolder) {
                RecyclerViewAdapter.MyViewHolder myViewHolder=
                        (RecyclerViewAdapter.MyViewHolder) viewHolder;
                mAdapter.onRowSelected(myViewHolder);
            }

        }

        super.onSelectedChanged(viewHolder, actionState);
    }
    @Override
    public void clearView(RecyclerView recyclerView,
                          RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);

        if (viewHolder instanceof RecyclerViewAdapter.MyViewHolder) {
            RecyclerViewAdapter.MyViewHolder myViewHolder=
                    (RecyclerViewAdapter.MyViewHolder) viewHolder;
            mAdapter.onRowClear(myViewHolder);
        }
    }

    public interface ItemTouchHelperContract {

        void onRowMoved(int fromPosition, int toPosition);
        void onRowSelected(RecyclerViewAdapter.MyViewHolder myViewHolder);
        void onRowClear(RecyclerViewAdapter.MyViewHolder myViewHolder);

    }

}

Here, we’ve defined an interface ItemTouchHelperContract. Each of its methods get called from the implemented methods of the ItemTouchHelper.Callback interface. The code for the RecyclerViewAdapter.java class is given below:

package com.journaldev.androidrecyclerviewdraganddrop;

import android.graphics.Color;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Collections;

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> implements ItemMoveCallback.ItemTouchHelperContract {

    private ArrayList<String> data;

    public class MyViewHolder extends RecyclerView.ViewHolder {

        private TextView mTitle;
        View rowView;

        public MyViewHolder(View itemView) {
            super(itemView);

            rowView = itemView;
            mTitle = itemView.findViewById(R.id.txtTitle);
        }
    }

    public RecyclerViewAdapter(ArrayList<String> data) {
        this.data = data;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview_row, parent, false);
        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.mTitle.setText(data.get(position));
    }


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


    @Override
    public void onRowMoved(int fromPosition, int toPosition) {
        if (fromPosition < toPosition) {
            for (int i = fromPosition; i < toPosition; i++) {
                Collections.swap(data, i, i + 1);
            }
        } else {
            for (int i = fromPosition; i > toPosition; i--) {
                Collections.swap(data, i, i - 1);
            }
        }
        notifyItemMoved(fromPosition, toPosition);
    }

    @Override
    public void onRowSelected(MyViewHolder myViewHolder) {
        myViewHolder.rowView.setBackgroundColor(Color.GRAY);

    }

    @Override
    public void onRowClear(MyViewHolder myViewHolder) {
        myViewHolder.rowView.setBackgroundColor(Color.WHITE);

    }
}


onRowMoved defined in the Contract interface earlier gets called when the drag and drop is done. Here we swap the positions of the two rows present in the ArrayList and call notifyItemMoved to refresh the adapter. The output of the above application in action is given below: android recyclerview drag drop output Up until now, we’ve done the drag and drop by pressing anywhere in the RecyclerView rows. Next, we’ll see how to do the same by pressing only a particular view inside the RecyclerView row.

Drag And Drop using Handles

In order to use a specific handle view to drag and drop we need to do the following things: Set isLongPressDragEnabled to false to disable the default drag and drop. Create an interface like:

public interface StartDragListener {
    void requestDrag(RecyclerView.ViewHolder viewHolder);
}

Implement it on the MainActivity and pass it to the Adapter.

@Override
    public void requestDrag(RecyclerView.ViewHolder viewHolder) {
        touchHelper.startDrag(viewHolder);
    }
mAdapter = new RecyclerViewAdapter(stringArrayList,this);

Inside the RecyclerViewAdapter.java do the following:

holder.imageView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() ==
                        MotionEvent.ACTION_DOWN) {
                    mStartDragListener.requestDrag(holder);
                }
                return false;
            }
        });

You can find the updated code in the download link at the end of this tutorial. The output of the application with the updated code is given below: android recyclerview drag drop handle output This brings an end to this tutorial. The complete source code of the project is given below:

AndroidRecyclerViewDragAndDrop

Github Project Link

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Anupam Chugh

author

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
JournalDev
DigitalOcean Employee
DigitalOcean Employee badge
February 1, 2022

Thanks a lot, This was a big help to me for understand about ItemTouchHelper.Callback library as a beginner, Also that “Drag And Drop using Handles” implementation is really impressive and it was like 2 birds from 1 shot for my knowledge. Again thanks a lot.

- Tharindu

    JournalDev
    DigitalOcean Employee
    DigitalOcean Employee badge
    July 6, 2021

    Not working with Horizontal RecyclerView. What should i do to make it work for HORIZONTAL view as well?

    - Raghav Sharma

      JournalDev
      DigitalOcean Employee
      DigitalOcean Employee badge
      December 22, 2020

      Is it possible to auto scroll recycleview while reaching at the bottom?

      - Mohit Dholakia

        JournalDev
        DigitalOcean Employee
        DigitalOcean Employee badge
        October 20, 2020

        Hi, Can’t able to drag more than one position. Can move only one position for each drag. How to fix?

        - Dhivya

          JournalDev
          DigitalOcean Employee
          DigitalOcean Employee badge
          July 14, 2020

          thanks brother its working for me.

          - Ahsaan Akhtar

            JournalDev
            DigitalOcean Employee
            DigitalOcean Employee badge
            July 8, 2020

            Dragging with large dataset causes serious lagging.Even the ui freezes for seconds!Any solutions for this?

            - Gugan Sakthivel

              JournalDev
              DigitalOcean Employee
              DigitalOcean Employee badge
              August 10, 2019

              I got this to work, except for the fact that the places aren’t saved. If I come back to the app/activity, they resent to numerical order. How do I get them to save their changed order, please?

              - Neth

                JournalDev
                DigitalOcean Employee
                DigitalOcean Employee badge
                April 10, 2019

                Thanks for share this, its a good example and easy to follow. Have a nice day!

                - Cesar Bibriesca

                  JournalDev
                  DigitalOcean Employee
                  DigitalOcean Employee badge
                  March 20, 2019

                  what if I want to use this in a fragment. I got error of “this”, in “mAdapter = new RecyclerViewAdapter(stringArrayList,this);”

                  - rohan

                    JournalDev
                    DigitalOcean Employee
                    DigitalOcean Employee badge
                    February 15, 2019

                    Thanks for the article. Helped me a lot.

                    - Prashant

                      Try DigitalOcean for free

                      Click below to sign up and get $200 of credit to try our products over 60 days!

                      Sign up

                      Join the Tech Talk
                      Success! Thank you! Please check your email for further details.

                      Please complete your information!

                      Become a contributor for community

                      Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

                      DigitalOcean Documentation

                      Full documentation for every DigitalOcean product.

                      Resources for startups and SMBs

                      The Wave has everything you need to know about building a business, from raising funding to marketing your product.

                      Get our newsletter

                      Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

                      New accounts only. By submitting your email you agree to our Privacy Policy

                      The developer cloud

                      Scale up as you grow — whether you're running one virtual machine or ten thousand.

                      Get started for free

                      Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

                      *This promotional offer applies to new accounts only.