Android RecyclerView Swipe To Delete

RecyclerView is a ViewGroup ,that display a scrolling list of elements based on large data sets (or data that frequently changes) . RecyclerView widget is more flexible and efficient version of ListView .

In the previous tutorial we have seen basic example of recyclerView , In this tutorial deleting items of recyclerView on swiping .




Project Detail
Project Name RecylerViewSwipeToDelete
Package com.tutorialsbuzz.recylerviewswipetodelete
Min Sdk Version 22
Target Sdk Version 29
Compile Sdk Version 29
Theme Theme.AppCompat.Light.DarkActionBar

ItemTouchHelper :

ItemTouchHelper is a utility class to add swipe to dismiss and drag & drop support to RecyclerView. It works with a RecyclerView and a Callback class, which configures what type of interactions are enabled and also receives events when user performs these actions.

Lets see example of swiping (LEFT and RIGHT) items of recyclerView

Add RecyclerView To XML Layout


Create XML Layout activity_main.xml , this will be set as content view for launcher Activity (MainActivity.kt) and add RecyclerView to your layout file .


file : activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/recyclerView"/>


Data Class


file : Model.kt
package com.tutorialsbuzz.recyclerview

data class Model(val name: String, val version:String) {}

To Load Data Into RecyclerView , We will read JSON File Kept Inside Asset folder and map it to above defined data class

file : main\assets\android_version.json
[
  {
    "name": "Cupcake",
    "version": "Android 1.5"
  },
  {
    "name": "Donut",
    "version": "Android 1.6"
  },
  {
    "name": "Eclairs",
    "version": "Android 2.0-2.1"
  },
  {
    "name": "Froyo",
    "version": "Android 2.2-2.3"
  },
  {
    "name": "Gingerbread",
    "version": "Android 2.3-2.3.7"
  },
  {
    "name": "Honeycomb",
    "version": "Android 3.0-3.2.6"
  },
  {
    "name": "Icecream",
    "version": "Android 4.0-4.0.4"
  },
  {
    "name": "Jellybean",
    "version": "Android 4.1-4.3.1"
  },
  {
    "name": "Kitkat",
    "version": "Android 4.4-4.4.4"
  },
  {
    "name": "Lolipop",
    "version": "Android 5.0-5.1.1"
  },
  {
    "name": "Marshmallow",
    "version": "Android 6.0-6.0.1"
  },
  {
    "name": "Nougat",
    "version": "Android 7.0-7.1.2"
  },
  {
    "name": "Oreo",
    "version": "Android 8.0-8.1"
  },
  {
    "name": "Pie",
    "version": "Android 9.0"
  }
]


Image Resource 

Name field from json matches to respective png file name kept inside drawable .

Folder : app\src\main\res\drawable

Adapter and ViewHolder For RecyclerView


1. XML Layout For RecyclerView Item

Create  XML Layout file in res/layout and name it row_item.xml .This Layout defines the layout for
Items of RecyclerView . Here In this example we have two TextView inside LinearLayout .

file : row_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="16dp"
        android:orientation="vertical">

    <ImageView android:layout_width="80dp"
               android:layout_height="80dp"
               android:id="@+id/img"
               android:contentDescription="@string/app_name"/>

    <TextView
            android:id="@+id/txt"
            android:textSize="22sp"
            android:text="Title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:layout_toEndOf="@+id/img"
            android:layout_marginStart="20dp"/>

    <TextView
            android:id="@+id/sub_txt"
            android:textSize="18sp"
            android:text="Title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textStyle="italic"
            android:layout_toEndOf="@+id/img"
            android:layout_below="@+id/txt"
            android:layout_marginStart="20dp"/>

</RelativeLayout>

2. Adapter

Create a Adapter That RecyclerView Can Use , Create a class CustomAdapter extend it to RecyclerView.Adapter .

3. ViewHolder 

Create Inner class ViewHolder extend it to RecyclerView.ViewHolder

file : CustomAdapter.kt
package com.tutorialsbuzz.recyclerview

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.tutorialsbuzz.recylerviewswipetodelete.R
import kotlinx.android.synthetic.main.row_item.view.*

class CustomAdapter(val modelList: List<Model>, val context: Context) :
    RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        (holder as ViewHolder).bind(modelList.get(position));
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val layoutInflater = LayoutInflater.from(parent.context)
        return ViewHolder(layoutInflater.inflate(R.layout.row_item, parent, false))
    }


    override fun getItemCount(): Int {
        return modelList.size;
    }

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        fun bind(model: Model): Unit {
            itemView.txt.text = model.name
            itemView.sub_txt.text = model.version

            val id = context.resources.getIdentifier(model.name.toLowerCase(), "drawable", context.packageName)
            itemView.img.setBackgroundResource(id)
        }

    }

}


ItemTouchHelper CallBack For RecyclerView 


Create an abstract class SwipeToDeleteCallback extend this class to ItemTouchHelper.Callback override the getMovementFlags , onMove method .
  1. getMovementFlags : Should return a composite flag which defines the enabled move directions in each state (idle, swiping, dragging).Instead of composing this flag manually, you can use makeMovementFlags(int, int) or makeFlag(int, int).For example, if you want it to allow swiping LEFT and RIGHT but only allow starting to swipe by swiping RIGHT, you can return

    override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
     val swipeFlag = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
     return makeMovementFlags(0, swipeFlag)
    }

  2. onMove : Called when onMove(RecyclerView, ViewHolder, ViewHolder) returns true , Upon receiving this callback, you should move the item from the old position to target position .
  3. onSwiped :  Called when a ViewHolder is swiped by the user. At this point, you should update your adapter (e.g. remove the item) and call related Adapter notify event.

file : SwipeToDeleteCallback.kt
package com.tutorialsbuzz.recylerviewswipetodelete

import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView

abstract class SwipeToDeleteCallback : ItemTouchHelper.Callback() {

    override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
        val swipeFlag = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
        return makeMovementFlags(0, swipeFlag)
    }

    override fun onMove(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder,
        target: RecyclerView.ViewHolder
    ): Boolean {
        return false
    }
}


Attaching ItemTouchHelper to RecyclerView .

  1. Creates an instance of ItemTouchHelper that will work with the given Callback.
  2. Call attachToRecyclerView on ItemTouchHelper instance by passing recyclerView.attachToRecyclerView Attaches the ItemTouchHelper to the provided RecyclerView.
val swipeToDeleteCallback = object : SwipeToDeleteCallback() {
 override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
  val pos = viewHolder.adapterPosition
  modelList.removeAt(pos)
  adapter.notifyItemRemoved(pos)
 }
}

val itemTouchHelper = ItemTouchHelper(swipeToDeleteCallback)
itemTouchHelper.attachToRecyclerView(recyclerView)

Activity

  1. Create a koltin class MainActivity.kt and extend it to AppCompatActivity class .
  2. Override onCreate function and set the content of this MainActivity with above defined xml layout (activity_main.xml). 
  3. Read JSON Data From Asset Folder , this will be used for binding data into RecyclerView .
  4. Set Vertical Linear LayoutManager to RecyclerView.
  5. Create Instance of Adapter and set to RecyclerView .
  6. Add CustomItemDecortion to RecyclerView .
  7. Create an instance of ItemTouchHelper by passing SwipeToDeleteCallback as parameter to its constructor.
  8. Attach ItemTouchHelper to RecyclerView .
file : MainActivity.kt
package com.tutorialsbuzz.recylerviewswipetodelete

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.tutorialsbuzz.recyclerview.CustomAdapter
import com.tutorialsbuzz.recyclerview.Model
import kotlinx.android.synthetic.main.activity_main.*
import org.json.JSONArray
import org.json.JSONObject

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val modelList = readFromAsset();
        val adapter = CustomAdapter(modelList, this)

        recyclerView.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
        recyclerView.adapter = adapter;
        recyclerView.addItemDecoration(SimpleDividerItemDecoration(this))

        val swipeToDeleteCallback = object : SwipeToDeleteCallback() {
            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
                val pos = viewHolder.adapterPosition
                modelList.removeAt(pos)
                adapter.notifyItemRemoved(pos)
            }
        }

        val itemTouchHelper = ItemTouchHelper(swipeToDeleteCallback)
        itemTouchHelper.attachToRecyclerView(recyclerView)
    }

    private fun readFromAsset(): MutableList<Model> {

        val modeList = mutableListOf<Model>()
        val bufferReader = application.assets.open("android_version.json").bufferedReader()
        val json_string = bufferReader.use {
            it.readText()
        }

        val jsonArray = JSONArray(json_string);

        for (i in 0..jsonArray.length() - 1) {
            val jsonObject: JSONObject = jsonArray.getJSONObject(i)
            val model = Model(jsonObject.getString("name"), jsonObject.getString("version"))
            modeList.add(model)
        }

        return modeList
    }

}



No comments:

Post a Comment