Introduction:
Let’s, first of all, see what is swipeable. Swipeable in terms of swiping items or elements both right and left side, to perform specific operations on it as shown in the sample output below. Before starting, let’s see what is Recycler View and when it should be used.
What is Recycler view?
Many apps need to display UI elements based on large data sets, or data that frequently changes. For example, a music app might need to display information about thousands of albums, but only a dozen of those albums might be on-screen at a time or an app like Gmail, which has lots of emails with different categories like sent and received etc. If the app created UI widgets for each of those albums or E-mails, the app would end up using a lot of memory and storage, potentially making the app slow and crash-prone. On the other hand, if the app created UI widgets each time a new album scrolled onto the screen and destroyed the widgets when it scrolled off, that would also cause the app to run slowly, since creating UI objects is a resource-intensive operation.
For this type of situations, we can use Recycler view, instead of List views to handle a large amount of data.
Why Swipeable Recycler View over simple one?
With swipeable recycler view, it would be easy to provide specific functionalities like edit an element or delete an element permanently etc.
Sample output:
Sample project: SwipableRecyclerView
Sample APK: Swipable RecyclerView_1.0
Seems Interesting right? So let’s get started!
Creating a New Project:
Open your Android Studio & create a new Project. For Kotlin support, check the checkbox of Kotlin support. Now give name whatever you like and We’ll keep all the things by default and clicked finish.
Adding Dependencies to Gradle:
To create recycler view, add following dependencies.
compile 'com.android.support:recyclerview-v7:25.3.1' compile 'com.android.support:design:25.3.1'
We don’t need any permissions from the user for Recycler view.
If your Android studio is not updated (lower version than 3.0), then you have to manually configure Kotlin. So add following line to your dependencies of a project (NOT module as above).
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
So the whole file will look like:
// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { ext.kotlin_version = '1.1.2-4' repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.3.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { jcenter() } } task clean(type: Delete) { delete rootProject.buildDir }
Now rebuild your project. Thus you’ve configured Kotlin manually! Now let’s go ahead.
Now add following `Kotlin` code in your main activity.
MainActivity.kt
package com.example.admin.swipablerecyclerview import android.content.DialogInterface import android.graphics.Bitmap import android.graphics.BitmapFactory import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.RectF import android.support.design.widget.FloatingActionButton import android.support.v7.app.AlertDialog import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.RecyclerView import android.support.v7.widget.helper.ItemTouchHelper import android.view.View import android.view.ViewGroup import android.widget.EditText import java.util.ArrayList class MainActivity : AppCompatActivity(), View.OnClickListener { private val names = ArrayList<String>() private var adapter: DataAdapter? = null private var recyclerView: RecyclerView? = null private var alertDialog: AlertDialog.Builder? = null private var et_name: EditText? = null private var edit_position: Int = 0 private var view: View? = null private var add = false private val p = Paint() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) initViews() initDialog() } private fun initViews() { val fab = findViewById(R.id.fab) as FloatingActionButton fab.setOnClickListener(this) recyclerView = findViewById(R.id.card_recycler_view) as RecyclerView recyclerView!!.setHasFixedSize(true) val layoutManager = LinearLayoutManager(applicationContext) recyclerView!!.layoutManager = layoutManager adapter = DataAdapter(names) recyclerView!!.adapter = adapter names.add("Kaushal") names.add("Alex") names.add("Ram") names.add("Abhishek") names.add("Narendra Modi") adapter!!.notifyDataSetChanged() initSwipe() } private fun initSwipe() { val simpleItemTouchCallback = object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) { override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { return false } override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { val position = viewHolder.adapterPosition if (direction == ItemTouchHelper.LEFT) { adapter!!.removeItem(position) } else { removeView() edit_position = position alertDialog!!.setTitle("Edit Name") et_name!!.setText(names[position]) alertDialog!!.show() } } override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) { val icon: Bitmap if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { val itemView = viewHolder.itemView val height = itemView.bottom.toFloat() - itemView.top.toFloat() val width = height / 3 if (dX > 0) { p.color = Color.parseColor("#388E3C") val background = RectF(itemView.left.toFloat(), itemView.top.toFloat(), dX, itemView.bottom.toFloat()) c.drawRect(background, p) icon = BitmapFactory.decodeResource(resources, R.drawable.ic_edit_white) val icon_dest = RectF(itemView.left.toFloat() + width, itemView.top.toFloat() + width, itemView.left.toFloat() + 2 * width, itemView.bottom.toFloat() - width) c.drawBitmap(icon, null, icon_dest, p) } else { p.color = Color.parseColor("#D32F2F") val background = RectF(itemView.right.toFloat() + dX, itemView.top.toFloat(), itemView.right.toFloat(), itemView.bottom.toFloat()) c.drawRect(background, p) icon = BitmapFactory.decodeResource(resources, R.drawable.ic_delete_white) val icon_dest = RectF(itemView.right.toFloat() - 2 * width, itemView.top.toFloat() + width, itemView.right.toFloat() - width, itemView.bottom.toFloat() - width) c.drawBitmap(icon, null, icon_dest, p) } } super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive) } } val itemTouchHelper = ItemTouchHelper(simpleItemTouchCallback) itemTouchHelper.attachToRecyclerView(recyclerView) } private fun removeView() { if (view!!.parent != null) { (view!!.parent as ViewGroup).removeView(view) } } private fun initDialog() { alertDialog = AlertDialog.Builder(this) view = layoutInflater.inflate(R.layout.dialog_layout, null) alertDialog!!.setView(view) alertDialog!!.setPositiveButton("Save") { dialog, which -> if (add) { add = false adapter!!.addItem(et_name!!.text.toString()) dialog.dismiss() } else { names[edit_position] = et_name!!.text.toString() adapter!!.notifyDataSetChanged() dialog.dismiss() } } et_name = view!!.findViewById(R.id.et_name) as EditText } override fun onClick(v: View) { when (v.id) { R.id.fab -> { removeView() add = true alertDialog!!.setTitle("Add Name") // et_country.setText(""); alertDialog!!.show() } } } }
Related:
Drag and Swipe with RecyclerView
Swipeable RecyclerView in Android
ItemDecoration in RecyclerView in Android
Parse JSON Data using Retrofit and Rxjava in android and display in Recyclerview using cardview
Parsing the Json Data using Android Retrofit Api and display in Recyclerview with Cardview
Note the method named,onSwiped()
here we are detecting swipe on the recycler view item and according to the direction of the swipe, we’ll decide the action: delete
or.edit
And using the method named method,onChildDraw()
we can draw the background of the element when it is swiped. We are creating an alert dialog when the user clicks on floating action button, for asking new name to be entered.When the user enters the new name we will notify recycler view to add that new name using method notifyDataSetChanged()
.
Here is our DataAdapter class.
DataAdapter.kt
package com.example.admin.swipablerecyclerview /** * Created by ADMIN on 5/26/2017. */ 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 internal class DataAdapter(private val names: ArrayList<String>) : RecyclerView.Adapter<DataAdapter.ViewHolder>() { override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): DataAdapter.ViewHolder { val view = LayoutInflater.from(viewGroup.context).inflate(R.layout.row_layout, viewGroup, false) return ViewHolder(view) } override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) { viewHolder.tv_names.text = names[i] } override fun getItemCount(): Int { return names.size } fun addItem(country: String) { names.add(country) notifyItemInserted(names.size) } fun removeItem(position: Int) { names.removeAt(position) notifyItemRemoved(position) notifyItemRangeChanged(position, names.size) } internal inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { var tv_names: TextView init { tv_names = view.findViewById(R.id.tv_names) as TextView } } }
Using this we are setting data items to recycler view. Below are the necessary layout files.
row_layout.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_marginBottom="1dp" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/tv_names" android:layout_marginTop="15sp" android:layout_marginBottom="15sp" android:layout_gravity="center" android:textSize="21sp" android:paddingTop="30sp" android:textAlignment="center" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textStyle="bold" /> </LinearLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.admin.swipablerecyclerview.MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/card_recycler_view" android:scrollbars="vertical" android:layout_width="match_parent" android:layout_height="match_parent"/> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:src="@drawable/ic_add" android:layout_marginLeft="16dp" android:layout_marginRight="16dp" android:layout_marginBottom="29dp" android:layout_alignParentBottom="true" android:layout_alignParentEnd="true" android:layout_marginEnd="27dp" /> </RelativeLayout>
dialog_layout.xml
<?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="match_parent"> <EditText android:id="@+id/et_name" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
Now run the app and you will able to see the recycler view with different names. Swipe left to delete and swipe right to edit the swiped item.
For more information: https://www.mytrendin.com/swipeable-recyclerview-android-using-kotlin/