How To Make A Drag-And-Drop Recyclerview In Android

Introduction

In this article, we’re going to learn how to implement drag and drop reordering inside a recyclerView.

Here, we implement dragging and dropping to reorganise the items in the recyclerView; simply long-press an item to drag it and drop it in the desired location.

Here, we first create the recyclerview using static data, and then we use the ItemTouchHelper to implement the drag and drop functionality.

Create Drag-and-Drop Recyclerview in Android

Step 1

Create a new project in the Android Studio and select an empty activity.

How To Make A Drag-And-Drop Recyclerview In Android

Step 2

Give the project a name, select the save location folder, and click on the finish button.

How To Make A Drag-And-Drop Recyclerview In Android

Step 3

Create the activity_main.xml file as shown below.

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

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

Step 4

Create the recycler_row.xml file in the layout folder for the recyclerview item.

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cardView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="2dp"
    app:cardBackgroundColor="#12dddd"
    app:cardCornerRadius="5dp"
    app:cardElevation="5dp"
    app:cardMaxElevation="5dp"
    app:cardPreventCornerOverlap="true"
    app:cardUseCompatPadding="true">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/lblItemName"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:layout_marginTop="10dp"
            android:text="Item Name"
            android:textColor="@color/black"
            android:textSize="18sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/lblItemDetails"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/lblItemName"
            android:layout_marginStart="10dp"
            android:layout_marginTop="15dp"
            android:drawablePadding="2dp"
            android:padding="5dp"
            android:text="Item Details" />
    </RelativeLayout>
</androidx.cardview.widget.CardView>

Step 5

Create the ItemModel.java class for item details that stores the item's name and its subdetails.

package com.uday.recyclerviewdragdrop;

public class ItemModel {
    private String Name;
    private String Detail;

    public ItemModel(String name, String detail) {
        Name = name;
        Detail = detail;
    }

    public String getName() {
        return Name;
    }

    public String getDetail() {
        return Detail;
    }

}

Step 6

Create the RecyclerViewAdapter.java class as follows:

package com.uday.recyclerviewdragdrop;

import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.Collections;
import java.util.List;

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewModel>
{

    private List<ItemModel> dataList;

    public void setDataList(List<ItemModel> dataList){
        this.dataList =  dataList;
    }

    @NonNull
    @Override
    public MyViewModel onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_row,parent,false);

        return new MyViewModel(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewModel holder, int position) {
        holder.lblItemName.setText(dataList.get(position).getName());
        holder.lblItemDetails.setText(dataList.get(position).getDetail());
    }

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

    class MyViewModel extends RecyclerView.ViewHolder{

        TextView lblItemName,lblItemDetails;
        CardView cardView;

        public MyViewModel(@NonNull View itemView) {

            super(itemView);
            lblItemName = itemView.findViewById(R.id.lblItemName);
            lblItemDetails = itemView.findViewById(R.id.lblItemDetails);
            cardView = itemView.findViewById(R.id.cardView);

        }
    }
}

Step 7

Create RecyclerRowMoveCallback.java and extends ItemTouchHelper.Callback as follows:

package com.uday.recyclerviewdragdrop;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;

public class RecyclerRowMoveCallback extends ItemTouchHelper.Callback {

    private RecyclerViewRowTouchHelperContract touchHelperContract;

    public RecyclerRowMoveCallback(RecyclerViewRowTouchHelperContract touchHelperContract){
        this.touchHelperContract = touchHelperContract;
    }

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

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

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

    @Override
    public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
        this.touchHelperContract.onRowMoved(viewHolder.getAdapterPosition(),target.getAdapterPosition());
        return false;
    }

    @Override
    public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) {
        if(actionState != ItemTouchHelper.ACTION_STATE_IDLE)
        {
            if(viewHolder instanceof RecyclerViewAdapter.MyViewModel){
                RecyclerViewAdapter.MyViewModel myViewHolder = (RecyclerViewAdapter.MyViewModel)viewHolder;
                touchHelperContract.onRowSelected(myViewHolder);
            }
        }
        super.onSelectedChanged(viewHolder, actionState);
    }

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

        if(viewHolder instanceof RecyclerViewAdapter.MyViewModel){
            RecyclerViewAdapter.MyViewModel myViewHolder = (RecyclerViewAdapter.MyViewModel)viewHolder;
            touchHelperContract.onRowClear(myViewHolder);
        }
    }

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

    }

    public interface RecyclerViewRowTouchHelperContract{
        void onRowMoved(int from,int to);
        void onRowSelected(RecyclerViewAdapter.MyViewModel myViewHolder);
        void onRowClear(RecyclerViewAdapter.MyViewModel myViewHolder);
    }
}

Step 8

Now implement the interface RecyclerRowMoveCallback.RecyclerViewRowTouchHelperContract in the RecyclerViewAdapter class. So after that, your adapter files look like the following:

package com.uday.recyclerviewdragdrop;

import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.Collections;
import java.util.List;

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewModel>
        implements RecyclerRowMoveCallback.RecyclerViewRowTouchHelperContract{

    private List<ItemModel> dataList;

    public void setDataList(List<ItemModel> dataList){
        this.dataList =  dataList;
    }

    @NonNull
    @Override
    public MyViewModel onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_row,parent,false);

        return new MyViewModel(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewModel holder, int position) {
        holder.lblItemName.setText(dataList.get(position).getName());
        holder.lblItemDetails.setText(dataList.get(position).getDetail());
    }

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

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

    @Override
    public void onRowSelected(MyViewModel myViewHolder) {
       myViewHolder.cardView.setCardBackgroundColor(Color.GRAY);
    }

    @Override
    public void onRowClear(MyViewModel myViewHolder) {
        myViewHolder.cardView.setCardBackgroundColor(Color.parseColor("#12dddd"));
    }

    class MyViewModel extends RecyclerView.ViewHolder{

        TextView lblItemName,lblItemDetails;
        CardView cardView;

        public MyViewModel(@NonNull View itemView) {

            super(itemView);
            lblItemName = itemView.findViewById(R.id.lblItemName);
            lblItemDetails = itemView.findViewById(R.id.lblItemDetails);
            cardView = itemView.findViewById(R.id.cardView);

        }
    }
}

Step 9

Now add the following code in MainActivity.java class

package com.uday.recyclerviewdragdrop;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Bundle;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    RecyclerView recyclerView;
    private ArrayList<ItemModel> list = new ArrayList();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Create Data For Recyclerview
        list.add(new ItemModel("Item 1","Item Detail 1"));
        list.add(new ItemModel("Item 2","Item Detail 2"));
        list.add(new ItemModel("Item 3","Item Detail 3"));
        list.add(new ItemModel("Item 4","Item Detail 4"));
        list.add(new ItemModel("Item 5","Item Detail 5"));
        list.add(new ItemModel("Item 6","Item Detail 6"));
        list.add(new ItemModel("Item 7","Item Detail 7"));
        list.add(new ItemModel("Item 8","Item Detail 8"));
        list.add(new ItemModel("Item 9","Item Detail 9"));

        recyclerView = findViewById(R.id.recyclerView);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        RecyclerViewAdapter adapter = new RecyclerViewAdapter();
        adapter.setDataList(list);

        ItemTouchHelper.Callback callback = new RecyclerRowMoveCallback(adapter);
        ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
        touchHelper.attachToRecyclerView(recyclerView);

        recyclerView.setAdapter(adapter);
    }
}

Step 10

Now run your app and drag and drop the item.

How To Make A Drag-And-Drop Recyclerview In Android

Summary

As you can see, the implementation of drag and drop reordering inside a recyclerView in Android is very simple.

In this article, we learned how to create a drag-and-drop recyclerview in Android.

And here I have also uploaded a demo project, so you can download it and try it for yourself.

Thank you for reading my article. Please leave your comments in the comment box below.

Enjoy Coding


Similar Articles