Kotlin RecyclerView Search Using EditText | Search Filter Android

kotlin sqlite multiple tables, kotlin recyclerview checkbox, kotlin recyclerview button, kotlin load html javascript, kotlin recyclerview searchview, kotlin recyclerview search using edittext, kotlin listview with edittext, kotlin recyclerview with edittext, kotlin swipe to delete listview, kotlin recyclerview swipe to delete, kotlin expandablelistview with checkbox, kotlin custom ratingbar, kotlin change tab, Kotlin Select Multiple Images From Gallery, Kotlin Custom Dialog With Image And Title, kotlin select multiple video

Kotlin RecyclerView Search Using EditText is today’s tutorial.

We will implement Search Filter functionality in recyclerview using Edit Text and Kotlin in Android.

This filter functionality helps user to find any row of recycler view easily. He just need to enter search query and results will sorted out automatically.

First of all, watch the video for more information.

 

Step 1. Brand New Project

Time to create a new project in the android studio with empty activity as the default one.

Also, do not forget to set Kotlin as the primary language.

Step 2. Gradle File

Let us add required lines in gradle file. Open your build.gradle(Module: app) file and add the below lines

 implementation 'com.android.support:recyclerview-v7:28.0.0'
 implementation 'com.android.support:cardview-v7:28.0.0'

Compiler will use the first line to download some files regarding recycler view. Second line is for card view.

Step 3. Drawable File

Now go to app->res->drawable directory. Make a new file and give it a name like cardview.xml

Copy the below code in cardview.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_focused="true">
        <shape android:shape="rectangle">
            <padding
                android:left="4dp"
                android:top="4dp"
                android:right="4dp"
                android:bottom="4dp"
                />
            <gradient android:startColor="#b71ca2" android:endColor="#cc2ec1" android:angle="270" />

            <corners android:topLeftRadius="4dp" android:topRightRadius="4dp"/>
        </shape>
    </item>

    <item android:state_focused="false"
        >
        <shape android:shape="rectangle">
            <padding
                android:left="4dp"
                android:top="4dp"
                android:right="4dp"
                android:bottom="4dp"
                />

            <gradient android:startColor="#b71ca2" android:endColor="#cc2ec1" android:angle="270" />

            <corners android:topLeftRadius="4dp" android:topRightRadius="4dp" />
        </shape>
    </item>

</selector>

This file is making some gradient effects with one or more colors.

Also, it is defining the corner radius for making circular corners. We will use this file to make our card view more attractive.

Step 4. Model and special XML file

For creating the view of the each row item of recycler view, we need to make a file which can be inflated by the adapter.

For this, go to app->res->layout directory and make a new XML file with name rv_item.xml

Add the below code snippet inside rv_item.xml file.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context=".MainActivity">

    <android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:id="@+id/card_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginTop="10dp"
        card_view:cardCornerRadius="4dp">

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

            <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/tv2"
                android:height="40dp"
                android:background="@drawable/cardview"
                android:gravity="center_vertical"
                android:paddingLeft="10dp"
                android:text=""
                android:textColor="#fff"
                android:textStyle="bold"
                android:textSize="18sp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/tv"
                android:height="40dp"
                android:gravity="center_vertical"
                android:paddingLeft="10dp"
                android:text="Image"
                android:textColor="#000"
                android:textStyle="bold"
                android:textSize="18sp" />



        </LinearLayout>

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

This file has two text views. Both of this text views are under the card view tag. Thus, a card view will be generated in each item of recycler view.

Now make a new Kotlin file and give it a name like SearchModel.kt

You need to add the following lines in SearchModel.kt

class SearchModel {

    var name: String? = null


    fun getNames(): String {
        return name.toString()
    }

    fun setNames(name: String) {
        this.name = name
    }
}

There is one string variable in this class. I have also added getter and setter for this variable. This model class will help us to maintain the proper data structure during the search process in the recycler view.

Step 5. Adapter Of Recycler View

Create another Kotlin File and give it a name like SearchAdapter.kt

SearchAdapter.kt file should contain the below source snippet

import android.content.Context
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

/**
 * Created by Parsania Hardik on 26-Jun-17.
 */
class SearchAdapter(ctx: Context, private val imageModelArrayList: ArrayList<SearchModel>) :
    RecyclerView.Adapter<SearchAdapter.MyViewHolder>() {

    private val inflater: LayoutInflater
    private val arraylist: ArrayList<SearchModel>

    init {

        inflater = LayoutInflater.from(ctx)
        this.arraylist = ArrayList<SearchModel>()
        this.arraylist.addAll(MainActivity.movieNamesArrayList)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchAdapter.MyViewHolder {

        val view = inflater.inflate(R.layout.rv_item, parent, false)

        return MyViewHolder(view)
    }

    override fun onBindViewHolder(holder: SearchAdapter.MyViewHolder, position: Int) {

        holder.time.setText(imageModelArrayList[position].getNames())
    }

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

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

        var time: TextView

        init {

            time = itemView.findViewById(R.id.tv) as TextView
        }

    }
}

First of all, see the following

 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchAdapter.MyViewHolder {

        val view = inflater.inflate(R.layout.rv_item, parent, false)

        return MyViewHolder(view)
    }

Above method is inflating the  rv_item.xml file.

So, every row item will get the view from this method.

Now read the below

  override fun onBindViewHolder(holder: SearchAdapter.MyViewHolder, position: Int) {

        holder.time.setText(imageModelArrayList[position].getNames())
    }

This method is setting the text to the text view. for this, it using the imageModelArrayList, which is our data source. We will create this arraylist in the main activity.

Step 6. Main Code Changes

Let us add some code lines in the main two files : activity_main.xml and MainActivity.kt

First of all, write the following snippet in the activity_main.xml file.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
              tools:context=".MainActivity">

    <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/editText"
            android:layout_alignParentTop="true"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:hint="enter query"
            android:singleLine="true">


        <requestFocus/>
    </EditText>

    <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="15dp"/>

</LinearLayout>

Only two UI widgets are there. One is edit text and another is recycler view.

Recycler view is located below the edit text so that it creates proper user experience.

Now write down the below code snippet in the MainActivity.kt file.

import android.content.Context
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import android.widget.EditText
import android.widget.Toast
import java.util.ArrayList

class MainActivity : AppCompatActivity() {

    private var recyclerView: RecyclerView? = null
    private var adapter: SearchAdapter? = null
    private var etsearch: EditText? = null
    private var moviewList: Array<String>? = null
    internal var textlength = 0

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

        moviewList = arrayOf(
            "Xmen",
            "Titanic",
            "Captain America",
            "Iron man",
            "Rocky",
            "Transporter",
            "Lord of the rings",
            "The jungle book",
            "Tarzan",
            "Cars",
            "Shreck"
        )

        recyclerView = findViewById(R.id.recycler) as RecyclerView

        movieNamesArrayList = populateList()
        Log.d("hjhjh", movieNamesArrayList.size.toString() + "")
        adapter = SearchAdapter(this, movieNamesArrayList)
        recyclerView!!.adapter = adapter
        recyclerView!!.layoutManager = LinearLayoutManager(applicationContext, LinearLayoutManager.VERTICAL, false)

        etsearch = findViewById(R.id.editText) as EditText
        array_sort = ArrayList<SearchModel>()
        array_sort = populateList()

        recyclerView!!.addOnItemTouchListener(
            RecyclerTouchListener(
                applicationContext,
                recyclerView!!,
                object : ClickListener {

                    override fun onClick(view: View, position: Int) {
                        Toast.makeText(this@MainActivity, array_sort[position].getNames(), Toast.LENGTH_SHORT).show()
                    }

                    override fun onLongClick(view: View?, position: Int) {

                    }
                })
        )


        etsearch!!.addTextChangedListener(object : TextWatcher {


            override fun afterTextChanged(s: Editable) {}

            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}

            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                textlength = etsearch!!.text.length
                array_sort.clear()
                for (i in movieNamesArrayList.indices) {
                    if (textlength <= movieNamesArrayList[i].getNames().length) {
                        Log.d("ertyyy", movieNamesArrayList[i].getNames().toLowerCase().trim())
                        if (movieNamesArrayList[i].getNames().toLowerCase().trim().contains(
                                etsearch!!.text.toString().toLowerCase().trim { it <= ' ' })
                        ) {
                            array_sort.add(movieNamesArrayList[i])
                        }
                    }
                }
                adapter = SearchAdapter(this@MainActivity, array_sort)
                recyclerView!!.adapter = adapter
                recyclerView!!.layoutManager =
                    LinearLayoutManager(applicationContext, LinearLayoutManager.VERTICAL, false)

            }
        })

    }

    private fun populateList(): ArrayList<SearchModel> {

        val list = ArrayList<SearchModel>()

        for (i in 0..7) {
            val imageModel = SearchModel()
            imageModel.setNames(moviewList!![i])
            list.add(imageModel)
        }

        return list
    }

    interface ClickListener {
        fun onClick(view: View, position: Int)

        fun onLongClick(view: View?, position: Int)
    }

    internal class RecyclerTouchListener(
        context: Context,
        recyclerView: RecyclerView,
        private val clickListener: ClickListener?
    ) : RecyclerView.OnItemTouchListener {

        private val gestureDetector: GestureDetector

        init {
            gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
                override fun onSingleTapUp(e: MotionEvent): Boolean {
                    return true
                }

                override fun onLongPress(e: MotionEvent) {
                    val child = recyclerView.findChildViewUnder(e.x, e.y)
                    if (child != null && clickListener != null) {
                        clickListener.onLongClick(child, recyclerView.getChildPosition(child))
                    }
                }
            })
        }

        override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {

            val child = rv.findChildViewUnder(e.x, e.y)
            if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
                clickListener.onClick(child, rv.getChildPosition(child))
            }
            return false
        }

        override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {}

        override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {

        }
    }

    companion object {
        lateinit var movieNamesArrayList: ArrayList<SearchModel>
        lateinit var array_sort: ArrayList<SearchModel>
    }

}

Going Deep In Above

Let us see the below

 private var recyclerView: RecyclerView? = null
    private var adapter: SearchAdapter? = null
    private var etsearch: EditText? = null
    private var moviewList: Array<String>? = null
    internal var textlength = 0

Compiler will create the objects of the various classes like Recycler View, SearchAdapter, Edit Text.

Then it will create one string arraylist which has the name : moviewList

At last, compiler will make one variable which has the value as “0”

Now, read the below code lines

   moviewList = arrayOf(
            "Xmen",
            "Titanic",
            "Captain America",
            "Iron man",
            "Rocky",
            "Transporter",
            "Lord of the rings",
            "The jungle book",
            "Tarzan",
            "Cars",
            "Shreck"
        )

Here, compiler will add some movie names into the arraylist moviewList

Focus on the below now

  movieNamesArrayList = populateList()
        Log.d("hjhjh", movieNamesArrayList.size.toString() + "")
        adapter = SearchAdapter(this, movieNamesArrayList)
        recyclerView!!.adapter = adapter
        recyclerView!!.layoutManager = LinearLayoutManager(applicationContext, LinearLayoutManager.VERTICAL, false)

Compiler will use the populateList() method to fill some data in movieNamesArrayList

Then compiler will initialize the adapter and it will bind this adapter to the recycler view.

Following is the coding lines for populateList() method.

  private fun populateList(): ArrayList<SearchModel> {

        val list = ArrayList<SearchModel>()

        for (i in 0..7) {
            val imageModel = SearchModel()
            imageModel.setNames(moviewList!![i])
            list.add(imageModel)
        }

        return list
    }

Here, compiler will create the arraylist with the objects of the SearchModel class.

Then it will make one for loop. During every iteration of this loop, it will create one object of SearchModel class and then it will set the name of movie to this object.

After this, it will add this object into the arraylist. Thus, this method is producing the data source.

Now see the below

 recyclerView!!.addOnItemTouchListener(
            RecyclerTouchListener(
                applicationContext,
                recyclerView!!,
                object : ClickListener {

                    override fun onClick(view: View, position: Int) {
                        Toast.makeText(this@MainActivity, array_sort[position].getNames(), Toast.LENGTH_SHORT).show()
                    }

                    override fun onLongClick(view: View?, position: Int) {

                    }
                })
        )

Compiler will execute the above when the user clicks the recycler view. It will simply show one Toast. This Toast contains the name of the movie which was clicked by the user.

Finally, see the below last snippet

  etsearch!!.addTextChangedListener(object : TextWatcher {


            override fun afterTextChanged(s: Editable) {}

            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}

            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                textlength = etsearch!!.text.length
                array_sort.clear()
                for (i in movieNamesArrayList.indices) {
                    if (textlength <= movieNamesArrayList[i].getNames().length) {
                        Log.d("ertyyy", movieNamesArrayList[i].getNames().toLowerCase().trim())
                        if (movieNamesArrayList[i].getNames().toLowerCase().trim().contains(
                                etsearch!!.text.toString().toLowerCase().trim { it <= ' ' })
                        ) {
                            array_sort.add(movieNamesArrayList[i])
                        }
                    }
                }
                adapter = SearchAdapter(this@MainActivity, array_sort)
                recyclerView!!.adapter = adapter
                recyclerView!!.layoutManager =
                    LinearLayoutManager(applicationContext, LinearLayoutManager.VERTICAL, false)

            }
        })

When the user enter any text in the edit text, compiler will run the onTextChanged() method.

In this method, compiler will get the search query from the edit text and then it will update the data source.

Then it will bind the data source to the recycler view and it will update it with filtered items.

Download Code Kotlin RecyclerView Search Using EditText

https://github.com/demonuts/Kotlin-RecyclerView-Search-Using-EditText-Search-Filter-Android