RecyclerView – Search and filter

In this chapter of the RecyclerView andorid tutorial we are going to implement how we can search in the titles of the items, which means we gonna implement a filter function.

First in this chapter, we are going to create a new fragment. This fragment will be a BottomSheetDialogFragment. It means, when we click on the Search FloatingActionButton, then the fragment slides up with the search fields.

GitHub

If you haven’t done the previous chapters, then from GitHub you can download the starter project for this chapter.

GitHub – modify_item branch

Step 1 – Create new fragment

The first step is to create a new fragment for the user interface of search. So click inside of the java, then the “com.inspirecoding.recyclerviewdemo” folders on the fragments package with the right mouse button. Then select New, move your mouse to the Fragment option, and from the submenu select Fragment (Blank). In the popup window name the fragment as “SearchFragment”, and click on the Finish button.

Android Studio gonna generate for us the fragment, but with some codes, what we don’t need. So delete them, and finally it should look like this.


SearchFragment

As you can see, the class is inherited from the class of Fragment. In our case we will have a BottomSheetDialog, so change the super class to BottomSheetDialogFragment.

Step 2 – UI of search

Next is to build up the user interface of the search fragment. Basically, Android Studio has opened it also, but you can do it from the res->layout folders. The name of the layout file is fragment_search.xml.

The user interface will be very simple, and it will use ConstraintLayout as the root ViewGroup.

Copy and paste the below code into the fragment_search.xml


fragment_search.xml

Note the blue horizontal line. We made it using a simple <view> tag. You can specify the width and the height. Then we can change the background to blue. The result is a thin blue horizontal line, which works inside of the UI like a separator.

Step 3 – Add to the navigation graph

Following in this step, we are going to add the SearchFragment to the navigation graph. Remember? In the chapter of the Navigation Component we have created an xml file, which contains all of the directions inside of this app.

So, open the navigation_grap.xml file from the res->navigation folders. Then, in Split or Design view click on the New Destionation button, what you can find at the top left corner.

From the list select the fragment_search option and move it to the recyclerFragment. In the code view navigate to the fragment and change the <fragment> tag to <dialog>.

Next, select the recyclerFragment, then drag the blue circle at the right side and drop it on the fragment_search. This will create the action between the 2 fragments.

Now, from the top menu select the Build option, then the last one, which is Rebuild Project. We have to do this, otherwise the code for the action won’t be generated and we can’t use it in the next step.

Step 4 – Open the search dialog

After, we created the action to open the search fragment, we have to add the click listener for the FloatingActionButton. So open the RecyclerFragment::class from the fragments package. Inside of the onViewCreated() method we have implemented the click listeners for 2 FABs already. We gonna handle the click of the search FAB also. 

So, copy and paste the below click listener at the end of the onViewCreated() method.


fab_search.setOnClickListener

Run the app

Before we can continue this chapter, we should test the implemented code. If you click on the FAB, then the 2 other FABs gonna be visible. So, click on the magnifying glass, and from the bottom of the screen the search fragment comes up. Still the search funtcion is not available in our app. So, if you type something in the text field, then nothing will happen.

Step 5 – The filter method

The next step is to implement the missing filter function. As before, it will be implemented in the ToDoViewModel::class. So, open it from the viewmodel package.

New variable

First, we gonna create a new list. This list will store the filtered results. Copy and paste the below list after the listOfToDos variable.

private var listOfToDos_full: MutableList<ToDo> =
mutableListOf()

From now on this collection will store the whole list of the items. It means we have to add it to the add, update and move methods.

addToDo()

Paste the below line at the top of this method.

listOfToDos_full.add(toDo)

updateToDo()

Again paste the below line at the top of this method.

listOfToDos_full.set(position, toDo)

updateToDo()

Finally, do the same here either. This method will look like this after adding the new collection.


AndroidManifest.xml
The filter method

Second is the implement the function, which will filter the list regarding the text of the search field from the SearchFragment.

Copy and paste the below code at the end of the ToDoViewModel::class.


filter

In Kotlin the basic filtering function is filter(). It returns the collection elements that match with the search text. Note that, we can refer the elements inside of the collection, and use the properties of the ToDo object to check, if the text of title contains the text.

Next, we have to clear the list, then add all the items from the filter result variable. Finally, we have to set the value of the LiveData as well to notify the obervers about the result.

Step 6 – Use the filter function

We are closer and closer to filter the list. Finally, we have to pass the string from the search text field to the above created filter method. 

First, we have to create an instance about the ToDoViewModel class in the SearchFragment::class. It means, that we have to make a member variable for it:


toDoViewModel

The EditText has a text changed listener, which gives us back the typed text. We will implement this listener inside of the onViewCreated() method. Just start typing the name of the method, and Android Studio will help you to implement easier the function.

So, copy and paste the below lines of code into the onViewCreated() method inside of the SearchFragment::class.


addTextChangedListener

Step 7 – Click listeners for the action buttons

Before we can run again the app, we should implement the click listeners for the action button of the search fragment. There we have a TextView, which will clear the search field, and a close button, which will dismiss the dialog, but the search field won’t be cleared.

So, copy and paste the below code after the change listener of the search field.


setOnClickListener

Run the app

If you run again the app, and add some items to the list, filter it using the search field. Then the list will be filtered.

But we do have a bug. When you filter the list and open up again the search sheet, then the text  of the filter will be gone, but the list is still filtered. Then, if you press the Clear text, nothing happens either.

So what we can do? 🤔  The solution is to save the state the filter text.

Step 8 – Save the state of the SearchFragment

To save the text from the SearchFragment, we will use a  ViewModel. Inside of this ViewModel we will have a String variable, which will store the text after we close the SearchFragment.

Create a new ViewModel

First, we have to create the ViewModel. So, click with the right mouse button on the viewmodel package, then select New, and from the list choose Kotlin file/class. In the popup window name the file as “SearchFragmentViewModel”.

Next, we must inherit the class from the ViewModel class.

class SearchFragmentViewModel: ViewModel()
{

}

Finally, create in the body of the class the below variable.

var searchText: String? = null

After the changes, the SearchFragmentViewModel::class looks like below.


SearchFragmentViewModel
Save the search text

The next step is to save the search text in the above created variable. For this first we have to create a member variable for the above created ViewModel. So, copy and paste the below line before the onCreateView() method.

private val searchFragmentViewModel
    by navGraphViewModels<SearchFragmentViewModel>(
        R.id.navigation_graph
    )

Fragments have there own lifecycle. When we close the SearchFragment, then the onDestroyView() will be fired. This will destroy the view, but still we can save here the search text.

So, again start typing the above mentioned function inside of the SearchFragment::class and create it. Then paste into its body the below line.

searchFragmentViewModel
    .searchText = et_search_text.text.toString()

Finally, the onDestroyView() method should look like below.


onDestroyView()
Get back the search text

To get back the search text and set it back into the search field, we can easly use the ViewModel. Inside of the onViewCreated() method paste the below code.


Get back the search text

Note the .let lambda call. This call provides us to avoid the crash of our app, if the value of the searchText variable is null. It can happen, when the list is not filtered.

Run the app

The last time in this chapter, run the app. If you type something in the filter, then you close the bottom sheet, and you come back, then the text should be there. Perfect. 

 

Congratulations! 😎

You just finished the RecyclerView tutorial.

 

 

GitHub

The source code is available on GitHub

GitHub – search_and_filter branch

Questions

I hope the description was understandable and clear. But if you have still questions, then leave me comments below! 😉

Have a nice a day! 🙂

 


 

Follow and like us:
Click to rate this post!
[Total: 0 Average: 0]

Leave a Reply

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