@@ -26,6 +26,8 @@ import androidx.compose.foundation.layout.fillMaxWidth
26
26
import androidx.compose.foundation.layout.padding
27
27
import androidx.compose.foundation.lazy.LazyColumn
28
28
import androidx.compose.foundation.rememberScrollState
29
+ import androidx.compose.foundation.text.input.TextFieldState
30
+ import androidx.compose.foundation.text.input.rememberTextFieldState
29
31
import androidx.compose.foundation.verticalScroll
30
32
import androidx.compose.material.icons.Icons
31
33
import androidx.compose.material.icons.filled.MoreVert
@@ -68,26 +70,32 @@ fun SearchBarExamples() {
68
70
var currentExample by remember { mutableStateOf<String ?>(null ) }
69
71
70
72
when (currentExample) {
71
- " basic " -> SearchBarBasicFilterList ()
72
- " advanced " -> AppSearchBar ()
73
+ " simple " -> SimpleSearchBarExample ()
74
+ " fancy " -> CustomizableSearchBarExample ()
73
75
else -> {
74
- Button (onClick = { currentExample = " basic " }) {
75
- Text (" Basic search bar with filter " )
76
+ Button (onClick = { currentExample = " simple " }) {
77
+ Text (" Simple SearchBar " )
76
78
}
77
- Button (onClick = { currentExample = " advanced " }) {
78
- Text (" Advanced search bar with filter " )
79
+ Button (onClick = { currentExample = " fancy " }) {
80
+ Text (" Customizable SearchBar " )
79
81
}
80
82
}
81
83
}
82
84
}
83
85
}
84
86
87
+ // [START android_compose_components_simple_searchbar]
85
88
@OptIn(ExperimentalMaterial3Api ::class )
86
- // [START android_compose_components_searchbarbasicfilterlist]
87
89
@Composable
88
- fun SearchBarBasicFilterList (modifier : Modifier = Modifier ) {
89
- var text by rememberSaveable { mutableStateOf(" " ) }
90
+ fun SimpleSearchBar (
91
+ textFieldState : TextFieldState ,
92
+ onSearch : (String ) -> Unit ,
93
+ searchResults : List <String >,
94
+ modifier : Modifier = Modifier
95
+ ) {
96
+ // Controls expansion state of the search bar
90
97
var expanded by rememberSaveable { mutableStateOf(false ) }
98
+
91
99
Box (
92
100
modifier
93
101
.fillMaxSize()
@@ -99,26 +107,28 @@ fun SearchBarBasicFilterList(modifier: Modifier = Modifier) {
99
107
.semantics { traversalIndex = 0f },
100
108
inputField = {
101
109
SearchBarDefaults .InputField (
102
- query = text,
103
- onQueryChange = { text = it },
104
- onSearch = { expanded = false },
110
+ query = textFieldState.text.toString(),
111
+ onQueryChange = { textFieldState.edit { replace(0 , length, it) } },
112
+ onSearch = {
113
+ onSearch(textFieldState.text.toString())
114
+ expanded = false
115
+ },
105
116
expanded = expanded,
106
117
onExpandedChange = { expanded = it },
107
- placeholder = { Text (" Hinted search text " ) }
118
+ placeholder = { Text (" Search " ) }
108
119
)
109
120
},
110
121
expanded = expanded,
111
122
onExpandedChange = { expanded = it },
112
123
) {
124
+ // Display search results in a scrollable column
113
125
Column (Modifier .verticalScroll(rememberScrollState())) {
114
- repeat(4 ) { index ->
115
- val resultText = " Suggestion $index "
126
+ searchResults.forEach { result ->
116
127
ListItem (
117
- headlineContent = { Text (resultText) },
118
- supportingContent = { Text (" Additional info" ) },
128
+ headlineContent = { Text (result) },
119
129
modifier = Modifier
120
130
.clickable {
121
- text = resultText
131
+ textFieldState.edit { replace( 0 , length, result) }
122
132
expanded = false
123
133
}
124
134
.fillMaxWidth()
@@ -128,27 +138,55 @@ fun SearchBarBasicFilterList(modifier: Modifier = Modifier) {
128
138
}
129
139
}
130
140
}
131
- // [END android_compose_components_searchbarbasicfilterlist ]
141
+ // [END android_compose_components_simple_searchbar ]
132
142
133
143
@Preview(showBackground = true )
134
144
@Composable
135
- private fun SearchBarBasicFilterListPreview () {
136
- SearchBarBasicFilterList ()
145
+ private fun SimpleSearchBarExample () {
146
+ // Create and remember the text field state
147
+ val textFieldState = rememberTextFieldState()
148
+ val items = listOf (
149
+ " Cupcake" , " Donut" , " Eclair" , " Froyo" , " Gingerbread" , " Honeycomb" ,
150
+ " Ice Cream Sandwich" , " Jelly Bean" , " KitKat" , " Lollipop"
151
+ )
152
+
153
+ // Filter items based on the current search text
154
+ val filteredItems by remember {
155
+ derivedStateOf {
156
+ val searchText = textFieldState.text.toString()
157
+ if (searchText.isEmpty()) {
158
+ emptyList()
159
+ } else {
160
+ items.filter { it.contains(searchText, ignoreCase = true ) }
161
+ }
162
+ }
163
+ }
164
+
165
+ SimpleSearchBar (
166
+ textFieldState = textFieldState,
167
+ onSearch = { /* Handle search submission */ },
168
+ searchResults = filteredItems
169
+ )
137
170
}
138
171
139
- // [START android_compose_components_searchbarfilterlist ]
172
+ // [START android_compose_components_customizable_searchbar ]
140
173
@OptIn(ExperimentalMaterial3Api ::class )
141
174
@Composable
142
- fun SearchBarFilterList (
143
- list : List <String >,
175
+ fun CustomizableSearchBar (
176
+ query : String ,
177
+ onQueryChange : (String ) -> Unit ,
178
+ onSearch : (String ) -> Unit ,
179
+ searchResults : List <String >,
180
+ onResultClick : (String ) -> Unit ,
181
+ // Customization options
182
+ placeholder : @Composable () -> Unit = { Text ("Search ") },
183
+ leadingIcon : @Composable (() -> Unit )? = { Icon (Icons .Default .Search , contentDescription = "Search ") },
184
+ trailingIcon : @Composable (() -> Unit )? = null,
185
+ supportingContent : (@Composable (String ) -> Unit )? = null,
186
+ leadingContent : (@Composable () -> Unit )? = null,
144
187
modifier : Modifier = Modifier
145
188
) {
146
- var text by rememberSaveable { mutableStateOf(" " ) }
147
- val filteredList by remember {
148
- derivedStateOf {
149
- list.filter { it.lowercase().contains(text.lowercase()) }
150
- }
151
- }
189
+ // Track expanded state of search bar
152
190
var expanded by rememberSaveable { mutableStateOf(false ) }
153
191
154
192
Box (
@@ -161,36 +199,36 @@ fun SearchBarFilterList(
161
199
.align(Alignment .TopCenter )
162
200
.semantics { traversalIndex = 0f },
163
201
inputField = {
202
+ // Customizable input field implementation
164
203
SearchBarDefaults .InputField (
165
- query = text,
166
- onQueryChange = { text = it },
167
- onSearch = { expanded = false },
204
+ query = query,
205
+ onQueryChange = onQueryChange,
206
+ onSearch = {
207
+ onSearch(query)
208
+ expanded = false
209
+ },
168
210
expanded = expanded,
169
211
onExpandedChange = { expanded = it },
170
- placeholder = { Text ( " Hinted search text " ) } ,
171
- leadingIcon = { Icon ( Icons . Default . Search , contentDescription = " Search " ) } ,
172
- trailingIcon = { Icon ( Icons . Default . MoreVert , contentDescription = " More options " ) },
212
+ placeholder = placeholder ,
213
+ leadingIcon = leadingIcon ,
214
+ trailingIcon = trailingIcon
173
215
)
174
216
},
175
217
expanded = expanded,
176
218
onExpandedChange = { expanded = it },
177
219
) {
220
+ // Show search results in a lazy column for better performance
178
221
LazyColumn {
179
- items(count = filteredList .size) { index ->
180
- val resultText = filteredList [index]
222
+ items(count = searchResults .size) { index ->
223
+ val resultText = searchResults [index]
181
224
ListItem (
182
225
headlineContent = { Text (resultText) },
183
- supportingContent = { Text (" Additional info" ) },
184
- leadingContent = {
185
- Icon (
186
- Icons .Filled .Star ,
187
- contentDescription = " Starred item"
188
- )
189
- },
226
+ supportingContent = supportingContent?.let { { it(resultText) } },
227
+ leadingContent = leadingContent,
190
228
colors = ListItemDefaults .colors(containerColor = Color .Transparent ),
191
229
modifier = Modifier
192
230
.clickable {
193
- text = resultText
231
+ onResultClick( resultText)
194
232
expanded = false
195
233
}
196
234
.fillMaxWidth()
@@ -199,10 +237,52 @@ fun SearchBarFilterList(
199
237
}
200
238
}
201
239
}
240
+ }
241
+ }
242
+ // [END android_compose_components_customizable_searchbar]
243
+
244
+ @Preview(showBackground = true )
245
+ @Composable
246
+ fun CustomizableSearchBarExample () {
247
+ // Manage query state
248
+ var query by rememberSaveable { mutableStateOf(" " ) }
249
+ val items = listOf (
250
+ " Cupcake" , " Donut" , " Eclair" , " Froyo" , " Gingerbread" , " Honeycomb" ,
251
+ " Ice Cream Sandwich" , " Jelly Bean" , " KitKat" , " Lollipop" , " Marshmallow" ,
252
+ " Nougat" , " Oreo" , " Pie"
253
+ )
254
+
255
+ // Filter items based on query
256
+ val filteredItems by remember {
257
+ derivedStateOf {
258
+ if (query.isEmpty()) {
259
+ items
260
+ } else {
261
+ items.filter { it.contains(query, ignoreCase = true ) }
262
+ }
263
+ }
264
+ }
265
+
266
+ Column (modifier = Modifier .fillMaxSize()) {
267
+ CustomizableSearchBar (
268
+ query = query,
269
+ onQueryChange = { query = it },
270
+ onSearch = { /* Handle search submission */ },
271
+ searchResults = filteredItems,
272
+ onResultClick = { query = it },
273
+ // Customize appearance with optional parameters
274
+ placeholder = { Text (" Search desserts" ) },
275
+ leadingIcon = { Icon (Icons .Default .Search , contentDescription = " Search" ) },
276
+ trailingIcon = { Icon (Icons .Default .MoreVert , contentDescription = " More options" ) },
277
+ supportingContent = { Text (" Android dessert" ) },
278
+ leadingContent = { Icon (Icons .Filled .Star , contentDescription = " Starred item" ) }
279
+ )
280
+
281
+ // Display the filtered list below the search bar
202
282
LazyColumn (
203
283
contentPadding = PaddingValues (
204
284
start = 16 .dp,
205
- top = 72 .dp,
285
+ top = 72 .dp, // Provides space for the search bar
206
286
end = 16 .dp,
207
287
bottom = 16 .dp
208
288
),
@@ -211,34 +291,9 @@ fun SearchBarFilterList(
211
291
traversalIndex = 1f
212
292
},
213
293
) {
214
- items(count = filteredList .size) {
215
- Text (text = filteredList [it])
294
+ items(count = filteredItems .size) {
295
+ Text (text = filteredItems [it])
216
296
}
217
297
}
218
298
}
219
299
}
220
- // [END android_compose_components_searchbarfilterlist]
221
-
222
- @Preview(showBackground = true )
223
- @Composable
224
- fun AppSearchBar (modifier : Modifier = Modifier ) {
225
- SearchBarFilterList (
226
- list = listOf (
227
- " Cupcake" ,
228
- " Donut" ,
229
- " Eclair" ,
230
- " Froyo" ,
231
- " Gingerbread" ,
232
- " Honeycomb" ,
233
- " Ice Cream Sandwich" ,
234
- " Jelly Bean" ,
235
- " KitKat" ,
236
- " Lollipop" ,
237
- " Marshmallow" ,
238
- " Nougat" ,
239
- " Oreo" ,
240
- " Pie"
241
- ),
242
- modifier
243
- )
244
- }
0 commit comments