Android Jetpack Compose Filter Tutorial

Β·

4 min read

Introduction

Hello! πŸ‘‹

In this small tutorial I will show you how to implement a simple list filter search using the latest Android Jetpack. πŸš€

Well then let's get started! 😎


Creating the Project

First we need to actually create the project, open up Android Studio and create a new project.

Compose

Make the new project a "Empty Compose Activity" and click on Next.

Next give your new project a name and click on Finish.

Project Name


Entering The Code

Now that we have the new project up and running. Creating a new directory in the root of the directory called "components" and create a new Kotlin file called "SearchBar.kt", this will be the component that has a text field and button that will allow the users to enter a search word.

package com.example.components

import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.example.searchbartutorial.R

@Composable
fun SearchBar(
    onSearch: (String) -> Unit
) {
    var searchQuery by remember {
        mutableStateOf("")
    }

    Column() {
        Row(modifier = Modifier.fillMaxWidth()) {
            TextField(
                value = searchQuery,
                onValueChange = { searchQuery = it },
                placeholder = { stringResource(id = R.string.search_bar_label) },
                modifier = Modifier.focusable(true),
                colors = TextFieldDefaults.textFieldColors(
                    backgroundColor = Color.Transparent,
                    focusedIndicatorColor = Color.Transparent,
                    unfocusedIndicatorColor = Color.Transparent
                ),
                maxLines = 1,
                leadingIcon = { Icon(Icons.Default.Search, contentDescription = "") }
            )

            Spacer(modifier = Modifier.width(10.dp))

            Button(
                onClick = {
                    onSearch(searchQuery)
                }
            ) {
                Text(text = stringResource(id = R.string.search_button))
            }
        }
    }
}

What this does is simply remember what the user searched for and when the user enters an input and clicks on Search it will call the function passed to it. The strings.xml file we are using is the following:

<resources>  
    <string name="app_name">SearchBarTutorial</string>  

    <!-- for search bar -->  
    <string name="search_bar_label">Enter keywords</string>  
    <string name="search_button">Search</string>  

    <!-- for home -->  
    <string name="no_users_text">No Users Found</string>  
</resources>

We also have the strings needed in the MainActivity for this.

Finally we need to actually use our newly created component in the Main Activity.

package com.example.searchbartutorial

import android.annotation.SuppressLint
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.components.SearchBar
import com.example.data.UserData
import com.example.searchbartutorial.ui.theme.SearchBarTutorialTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            SearchBarTutorialTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    MainScreen()
                }
            }
        }
    }
}

@SuppressLint("UnrememberedMutableState", "MutableCollectionMutableState")
@Composable
fun MainScreen() {
    val users = mutableStateListOf<UserData>()
    val user1 = UserData(1, "ethan")
    val user2 = UserData(2, "bob")
    var filteredUsers = remember {
        mutableStateOf(mutableListOf<UserData>(user1, user2))
    }

    users.add(user1)
    users.add(user2)

    Scaffold() {
        Column {
            Spacer(modifier = Modifier.height(20.dp))

            SearchBar(onSearch = {
                val result = users.filter { user ->
                    user.name.lowercase().contains(it.lowercase())
                }

                if (result.isNotEmpty()) {
                    filteredUsers.value = result.toMutableStateList()
                } else {
                    filteredUsers.value = mutableListOf<UserData>()
                }
            })

            Spacer(modifier = Modifier.height(10.dp))

            if (filteredUsers.value.size == 0) {
                Text(
                    text = stringResource(id = R.string.no_users_text),
                    fontWeight = FontWeight.Bold,
                    textAlign = TextAlign.Center,
                    modifier = Modifier.fillMaxWidth(),
                    fontSize = 22.sp
                )

                return@Column
            }

            filteredUsers.value.map {
                Text(
                    text = it.name,
                    fontWeight = FontWeight.Bold,
                    fontSize = 22.sp,
                    textAlign = TextAlign.Center,
                    modifier = Modifier.fillMaxWidth()
                )

                Spacer(modifier = Modifier.height(5.dp))
            }
        }
    }
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    SearchBarTutorialTheme {
        MainScreen()
    }
}

Here we actually use our newly created SearchBar component to filter a user list. ☺️ We also need to make sure to handle when no users are found.

That's it. With just a little bit of code we were able to filter a list of users. 😎


Conclusion

Here I have shown how to implement a simple using search filter. I actually needed to something like this for work and I had a lot of problems with Exceptions etc, so I decided to write this up for my future self and I hope this is of use to you so you don't make the same mistakes I did. 😣

You can also find the source code for this directory here: https://github.com/ethand91/android-compose-filter

Link to the original article: https://ethan-dev.com/post/android-jetpack-compose-filter-tutorial


Like me work? I post about a variety of topics, if you would like to see more please like and follow me. Also I love coffee.

β€œBuy Me A Coffee”

If you are looking to learn Algorithm Patterns to ace the coding interview I recommend the following course: https://algolab.so/p/algorithms-and-data-structure-video-course?affcode=1413380_bzrepgch

Did you find this article valuable?

Support Ethan by becoming a sponsor. Any amount is appreciated!

Β