Sun. Jan 20th, 2019

Drag and Swipe with RecyclerView

This tutorial explains how to implement swipe and drag gestures with items in RecyclerView. We will do this in two parts. Firstly, we will create a list of some food items with the help of RecyclerView and then we will add swipe and drag functionality to these items with the help of a class called ItemTouchHelper.

Output –

 

Download Project – here

Download APK – here

If you are a beginner, learn android

Creating a new Project –

Open Android Studio and create a new project – Recycler View. Navigate through next windows, choose an empty activity, click next and then click finish.

Pre – Requisites –

For using RecyclerView in our application we need to add its dependency –

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

For using CardView, the dependency is –

compile 'com.android.support:cardview-v7:25.3.1'

Add these lines below other dependencies in build.gradle(Module: app) file. Checkout the latest version of these dependencies before adding them. At the time of making this tutorial, 25.3.1 is the latest version.

Part 1 – Creating the List with the help of RecyclerView –

Create RecyclerView –

Let’s create the layout of main activity (where we have to view the list) first. Jump to activity_main in layouts directory. Add RecyclerView within ScrollView. Your layout should look something like this –

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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="wrap_content"
    tools:context="com.example.gurkirat.recyclerview.MainActivity">

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

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

    </ScrollView>

</LinearLayout>

Create the list item to be used in RecyclerView –

Create a new layout resource file in layout directory, name it as list_item. This list item can be customized according to your choice. I have used a CardView which consists of an image with some text (using ImageView and TextView).

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="4dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <ImageView
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_margin="20dp"
            android:layout_gravity="center"
            android:id="@+id/imgFood"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/txtFood"
            android:layout_gravity="center"
            android:layout_margin="20dp"
            android:textSize="17sp"/>
    </LinearLayout>

    </android.support.v7.widget.CardView>

</LinearLayout>

Creating the bean class for list item –

This is the class that corresponds to the list item we created. This is a bean class or model class for our object that represents how our object will look like. We create two member variables – foodItem and imgId – and generate their getters and setters (alt + insert -> generate -> getters and setters -> select both -> ok).

package com.example.gurkirat.recyclerview;

public class FoodItemBean {
    private String foodItem;
    private int imgId;

    public String getFoodItem() {
        return foodItem;
    }

    public void setFoodItem(String foodItem) {
        this.foodItem = foodItem;
    }

    public int getImgId() {
        return imgId;
    }

    public void setImgId(int imgId) {
        this.imgId = imgId;
    }
}

Creating the data source –

Now we want some dummy data to fill our list. It is actually not necessary to create this class until you are not having any data source. If you have some database or data coming from online sources then there is no need to create this class. Simply get that data in ArrayList in MainActivity and pass it into adapter call (we’ll learn to pass data into adapter later in this tutorial). But if no data is available you can simply generate dummy data with the help of this class.

package com.example.gurkirat.recyclerview;

import java.util.ArrayList;
import java.util.List;

public class DataSource {

    private static final String[] foodItems = {"Burger", "Pasta", "Chocolates", "Ice Cream"};

    private static final int[] foodImages = {R.drawable.burger, R.drawable.pasta,R.drawable.choc,R.drawable.icecream};

    public static List<FoodItemBean> createListItems(){

        List<FoodItemBean> items = new ArrayList<>();

        for(int i = 0; i < 3; i++){
            for(int j = 0; j < foodItems.length && j < foodImages.length; j++){

                FoodItemBean foodItemBean = new FoodItemBean();

                foodItemBean.setFoodItem(foodItems[j]);
                foodItemBean.setImgId(foodImages[j]);

                items.add(foodItemBean);
            }
        }

        return items;
    }

}

Create a string array (for storing names of the food item) and integer array (for storing resource Id’s of images to be displayed).

The function createListItems() with a return type of List<FoodItemBean> generates the objects of type FoodItemBean with the help of double for loop. This function can generate any number of objects by changing the value of I in outer for loop. The objects(items) are added to list ‘items’ which is returned on the call of the function.

Create the Adapter for RecyclerView – 

package com.example.gurkirat.recyclerview;

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

import java.util.List;

public class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.ViewHolder>{

    List<FoodItemBean> foodItemList;

    public FoodAdapter(List<FoodItemBean> foodItemList){
        this.foodItemList = foodItemList;
    }

    public class ViewHolder extends RecyclerView.ViewHolder{

        ImageView imgFood;
        TextView txtFood;

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

            imgFood = (ImageView)itemView.findViewById(R.id.imgFood);
            txtFood = (TextView)itemView.findViewById(R.id.txtFood);

        }

    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
        ViewHolder viewHolder = new ViewHolder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(FoodAdapter.ViewHolder holder, int position) {
        FoodItemBean foodItemBean = foodItemList.get(position);

        holder.imgFood.setImageResource(foodItemBean.getImgId());
        holder.txtFood.setText(foodItemBean.getFoodItem());
    }

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


}

We will create a FoodAdapter class that extends the RecylerView.Adapter<FoodAdapter.ViewHolder>. ViewHolder actually helps the RecyclerView’s adapter (FoodAdapter here) to have access to the views currently held by ViewHolder. As soon as we extend RecylerView.Adapter we get an error. We then override its method to remove the error. We will see an explanation of these methods later.

List<FoodItemBean> foodItemList;

public FoodAdapter(List<FoodItemBean> foodItemList){
    this.foodItemList = foodItemList;
}

Initially, create a constructor of adapter class. This constructor takes in a list that consists of data(objects) that will be bound on views.

    public class ViewHolder extends RecyclerView.ViewHolder{

        ImageView imgFood;
        TextView txtFood;

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

            imgFood = (ImageView)itemView.findViewById(R.id.imgFood);
            txtFood = (TextView)itemView.findViewById(R.id.txtFood);

        }

    }

Create a class ViewHolder that extends built-in RecyclerView.ViewHolder. Two variables imgFood and txtFood are initialized. Then the constructor of the class is created that takes in the itemView and extracts ImageView and TextView from that itemView. The ViewHolder holds these views.

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
    ViewHolder viewHolder = new ViewHolder(view);
    return viewHolder;
}

This method inflates the XML views i.e it will render the views by creating their objects in memory. In simple terms, LayoutInflator will convert the XML from R.layout.list_item into a view that we will pass into the constructor of ViewHolder. This method returns the viewHolder object.

@Override
    public void onBindViewHolder(FoodAdapter.ViewHolder holder, int position) {
        FoodItemBean foodItemBean = foodItemList.get(position);

        holder.imgFood.setImageResource(foodItemBean.getImgId());
        holder.txtFood.setText(foodItemBean.getFoodItem());
    }

This method takes in the ViewHolder’s object and position of the current item. It simply binds the data on that position of the object, to the views of the holder.

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

This method just returns the size of the list of food items.

Related:

Swipeable RecyclerView in Android using Kotlin.

Detecting Swipe Gestures Android Tutorial

Swipeable RecyclerView in Android

Android ViewPager to Swipe the Screen Left or Right

ItemDecoration in RecyclerView in Android

The MainActivity –

package com.example.gurkirat.recyclerview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import com.example.gurkirat.recyclerview.R;
import com.example.gurkirat.recyclerview.FoodAdapter;
import com.example.gurkirat.recyclerview.DataSource;
import com.example.gurkirat.recyclerview.FoodItemBean;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    RecyclerView rvFoodItems;
    FoodAdapter foodAdapter;
    ArrayList<FoodItemBean> foodList;

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

        foodList = (ArrayList)DataSource.createListItems();
        foodAdapter = new FoodAdapter(foodList);

        rvFoodItems = (RecyclerView)findViewById(R.id.rvFoodItems);
        rvFoodItems.setLayoutManager(new LinearLayoutManager(this));
        rvFoodItems.setItemAnimator(new DefaultItemAnimator());
        rvFoodItems.setAdapter(foodAdapter);

}

In this activity, create an instance of ArrayList, FoodAdapter, and RecyclerView each. In onCreate, call the method createListItems() from DataSource class and store the returned list in a foodList variable.  Then create the object of FoodAdapter and pass foodList in it. After that initialize the RecyclerView. Set LayoutManager, ItemAnimator, and Adapter on it as shown.

So, we have successfully made a working RecyclerView. Now we need to add Swipe and Drag functionality to it.

Part 2 – Adding Swipe and Drag functionality –

In the MainActivity, add following code in onCreate –

ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT){

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

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        deleteItem(viewHolder.getAdapterPosition());
    }
    
});
itemTouchHelper.attachToRecyclerView(rvFoodItems);

Class ItemTouchHelper helps to swipe and drag the list view items. The parameter ItemTouchHelper.UP | ItemTouchHelper.DOWN enables dragging the view up and down. If set to zero, the view cannot be dragged. Another parameter ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT enables swiping of the view.

The method onMove(..) tells what will happen if the view is dragged up or down. It is defined by a custom method moveItem(..) which is explained shortly. The method onSwiped(..) tells what will be the change in data set after swiping the view. Method deleteItem(..) is also explained shortly.

At last, an object of ItemTouchHelper is attached to RecyclerView as shown.

Method moveItem(viewHolder.getAdapterPosition(),target.getAdapterPosition()) –

void moveItem(int oldPos, int newPos){
    FoodItemBean fooditem = foodList.get(oldPos);

    foodList.remove(oldPos);
    foodList.add(newPos, fooditem);
    foodAdapter.notifyItemMoved(oldPos, newPos);
}

This method removes the item in foodList from old position and adds it to the new position. After which it notifies the adapter about change in position.

Method deleteItem(viewHolder.getAdapterPosition()) – 

void deleteItem(final int position){
    foodList.remove(position);
    foodAdapter.notifyItemRemoved(position);
}

This method removes swiped item from foodList and notifies the adapter.

After all, this is done our MainActivity will look something like this –

package com.example.gurkirat.recyclerview;

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

import com.example.gurkirat.recyclerview.R;
import com.example.gurkirat.recyclerview.FoodAdapter;
import com.example.gurkirat.recyclerview.DataSource;
import com.example.gurkirat.recyclerview.FoodItemBean;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    RecyclerView rvFoodItems;
    FoodAdapter foodAdapter;
    ArrayList<FoodItemBean> foodList;

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

        foodList = (ArrayList)DataSource.createListItems();

        rvFoodItems = (RecyclerView)findViewById(R.id.rvFoodItems);
        rvFoodItems.setLayoutManager(new LinearLayoutManager(this));
        rvFoodItems.setItemAnimator(new DefaultItemAnimator());

        foodAdapter = new FoodAdapter(foodList);
        rvFoodItems.setAdapter(foodAdapter);

        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
                ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT){

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

            @Override
            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
                deleteItem(viewHolder.getAdapterPosition());
            }
        });
        itemTouchHelper.attachToRecyclerView(rvFoodItems);

    }


    void moveItem(int oldPos, int newPos){
        FoodItemBean fooditem = foodList.get(oldPos);

        foodList.remove(oldPos);
        foodList.add(newPos, fooditem);
        foodAdapter.notifyItemMoved(oldPos, newPos);
    }

    void deleteItem(final int position){
        foodList.remove(position);
        foodAdapter.notifyItemRemoved(position);
    }


}

That is it. We are done with Swipe and Drag functionality also.

At last our Manifest file –

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.gurkirat.recyclerview">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Conclusion –

We have learned about how to view linear list items with the help of RecyclerView. Also, we have learned about Swipe and Drag functionality for the same. This same functionality can also be applied to StaggeredGridLayout or GridLayoutManager. In the case of any queries, you may ask questions. Keep following more amazing Android Blogs.


If you really liked the article, please subscribe to our YouTube Channel for videos related to this article.Please find us on Twitter and Facebook.

Leave a Reply

Your email address will not be published. Required fields are marked *