In this Jetpack compose tutorial we will learn how to Create Search View with Jetpack compose in Android application.
Search View is basically a text field where user will type any thing and according to value typed in the text field , given below list will be filtered.
Let's get started
Step 1: Create android application in android studio
Step 2: Follow step for setup Jetpack Compose with Android Studio
In this example we are managing the data inside listview with Viewmodel and kotlin data classes
Lets create search Item Data
data class SearchData(var name: String? = null, var emailId: String? = null) |
View Model
package com.example.jetpack.viewmodels import android.app.Application import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import com.example.jetpack.widget.SearchData import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch import java.util.* import kotlin.collections.ArrayList class SearchViewModel(appObj: Application) : AndroidViewModel(appObj) { private val _searchList = MutableStateFlow(listOf()) val list = arrayListOf( SearchData( name = "Ankit Singh", emailId = "an@gmail.com" ), SearchData( name = "Neha Shaw", emailId = "ne@gmail.com" ), SearchData( name = "Arpita Ghosh", emailId = "ar@gmail.com" ), SearchData( name = "Akash Tiwari", emailId = "ak@gmail.com" ), SearchData( name = "Anisha Tiwari", emailId = "an@gmail.com" ), SearchData( name = "Rowdy Rathore", emailId = "ro@gmail.com" ), SearchData( name = "Jit Singh", emailId = "ji@gmail.com" ), SearchData( name = "Pravin Raj", emailId = "pr@gmail.com" ), SearchData( name = "Sneha Rao", emailId = "sn@gmail.com" ), SearchData( name = "Ranjana Rathore", emailId = "ran@gmail.com" ), SearchData( "Kamala Rathore", emailId = "ka@gmail.com" ) ) val searchList: StateFlow> get() = _searchList fun searchedItems(searchedText: String) { if (searchedText.isNotEmpty()) { val resultList = ArrayList() for (data in list) { if (data.name?.lowercase(Locale.getDefault()) ?.contains(searchedText, ignoreCase = true) == true ) { resultList.add(data) } } _searchList.value = resultList } else { _searchList.value = list } } init { fetchList() } private fun fetchList() { viewModelScope.launch { _searchList.emit(list) } } } |
Here we have used stateFlow which emits list of serachData whenever search data will changed that can be observed while showing list items.
Lets create UI to display data inside listview
@Composable fun SearchListItem(searchData: SearchData) { Card( modifier = Modifier .padding(top = 16.dp) .fillMaxWidth(), elevation = 4.dp, border = BorderStroke(width = 1.2.dp, Color.Blue) ) { Row(content = { Icon( Icons.Default.Contacts, "", tint = Color.Blue, modifier = Modifier .padding(start = 16.dp, top = 16.dp) ) Column(modifier = Modifier.padding(16.dp)) { Text( text = "${searchData.name}", style = TextStyle( color = Color.Blue, fontSize = 21.sp, fontWeight = FontWeight.Bold ) ) Text(text = "${searchData.emailId}", modifier = Modifier.padding(top = 8.dp)) } }) } } |
Let's create ui for SearchView ( we will create search view with prefix icon as magnifying glass, in the middle we will use text field and in the end cross icon) with SearchViewTextField composable function where we are going the pass the mutable state so that whenever user type any thing it will be save in state and according to typed data list will be rendered.
@Composable fun SearchViewTextField(state: MutableState) { Box( modifier = Modifier .border(width = 1.dp, color = Color.Gray, shape = CircleShape) .fillMaxWidth() ) { BasicTextField( value = state.value, onValueChange = { state.value = it }, modifier = Modifier .background(Color.White, CircleShape) .height(38.dp) .fillMaxWidth(), singleLine = true, maxLines = 1, decorationBox = { innerTextField -> Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(horizontal = 10.dp) ) { Icon( imageVector = Icons.Default.Search, contentDescription = "image", tint = Color.Blue ) Box( modifier = Modifier.weight(1f), contentAlignment = Alignment.CenterStart ) { if (state.value == TextFieldValue("")) Text( "Search" ) innerTextField() } if (state.value != TextFieldValue("")) { IconButton( onClick = { state.value = TextFieldValue("") }, ) { Icon( imageVector = Icons.Default.Close, contentDescription = "image", tint = Color.Blue ) } } } } ) } } |
Create top App bar
TopAppBar( title = { Text("Search View Demo") } )
|
Lets combine Viewmodel, SearchView, List together and top app bar
@Composable fun SearchViewDemo(searchViewModel: SearchViewModel) { JetPackTheme( ) { Scaffold( modifier = Modifier.fillMaxSize(), content = { SearchContent(searchViewModel) }, topBar = { TopAppBar( title = { Text("Search View Demo") } ) } ) } } @Composable fun SearchContent(searchViewModel: SearchViewModel) { val searchList = searchViewModel.searchList.collectAsState() val searchBy = remember { mutableStateOf(TextFieldValue("")) } Column( Modifier .padding(top = 16.dp, start = 16.dp, end = 16.dp) .fillMaxSize() ) { SearchViewTextField(searchBy) searchViewModel.searchedItems(searchBy.value.text) LazyColumn( contentPadding = PaddingValues( bottom = 100.dp ) ) { items( items = searchList.value, itemContent = { SearchListItem(searchData = it) }) } } }
|
Complete example code to implement searchview to search the listview items with jetpack compose
package com.example.jetpack import android.os.Bundle import android.view.WindowManager import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Contacts import androidx.compose.material.icons.filled.Search import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.ViewModelProvider import com.example.jetpack.ui.theme.JetPackTheme import com.example.jetpack.viewmodels.SearchViewModel import com.example.jetpack.widget.SearchViewDemo class MainActivity : ComponentActivity() { @ExperimentalMaterialApi @ExperimentalFoundationApi override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) val searchViewModel = ViewModelProvider(this).get(SearchViewModel::class.java) setContent { SearchViewDemo(searchViewModel) } } } @ExperimentalMaterialApi @ExperimentalFoundationApi @Preview(showBackground = true) @Composable fun DefaultPreview() { } @Composable fun SearchViewDemo(searchViewModel: SearchViewModel) { JetPackTheme( ) { Scaffold( modifier = Modifier.fillMaxSize(), content = { SearchContent(searchViewModel) }, topBar = { TopAppBar( title = { Text("Search View Demo") } ) } ) } } @Composable fun SearchContent(searchViewModel: SearchViewModel) { val searchList = searchViewModel.searchList.collectAsState() val searchBy = remember { mutableStateOf(TextFieldValue("")) } Column( Modifier .padding(top = 16.dp, start = 16.dp, end = 16.dp) .fillMaxSize() ) { SearchViewTextField(searchBy) searchViewModel.searchedItems(searchBy.value.text) LazyColumn( contentPadding = PaddingValues( bottom = 100.dp ) ) { items( items = searchList.value, itemContent = { com.example.jetpack.widget.SearchListItem(searchData = it) }) } } } @Composable fun SearchListItem(searchData: SearchData) { Card( modifier = Modifier .padding(top = 16.dp) .fillMaxWidth(), elevation = 4.dp, border = BorderStroke(width = 1.2.dp, Color.Blue) ) { Row(content = { Icon( Icons.Default.Contacts, "", tint = Color.Blue, modifier = Modifier .padding(start = 16.dp, top = 16.dp) ) Column(modifier = Modifier.padding(16.dp)) { Text( text = "${searchData.name}", style = TextStyle( color = Color.Blue, fontSize = 21.sp, fontWeight = FontWeight.Bold ) ) Text(text = "${searchData.emailId}", modifier = Modifier.padding(top = 8.dp)) } }) } } @Composable fun SearchViewTextField(state: MutableState) { Box( modifier = Modifier .border(width = 1.dp, color = Color.Gray, shape = CircleShape) .fillMaxWidth() ) { BasicTextField( value = state.value, onValueChange = { state.value = it }, modifier = Modifier .background(Color.White, CircleShape) .height(38.dp) .fillMaxWidth(), singleLine = true, maxLines = 1, decorationBox = { innerTextField -> Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(horizontal = 10.dp) ) { Icon( imageVector = Icons.Default.Search, contentDescription = "image", tint = Color.Blue ) Box( modifier = Modifier.weight(1f), contentAlignment = Alignment.CenterStart ) { if (state.value == TextFieldValue("")) Text( "Search" ) innerTextField() } if (state.value != TextFieldValue("")) { IconButton( onClick = { state.value = TextFieldValue("") }, ) { Icon( imageVector = Icons.Default.Close, contentDescription = "image", tint = Color.Blue ) } } } } ) } } data class SearchData(var name: String? = null, var emailId: String? = null) |
Images
Article Contributed By :
|
|
|
|
2958 Views |