Skip to content

Commit e6997d9

Browse files
Adding SearchBar examples (#408)
* Adding SearchBar examples * Apply Spotless * Add search bar examples to top compose examples * Add content descriptions * Delete shared/build/generated/res/pngs/debug/drawable-anydpi-v24/ic_launcher_foreground.xml * remove errant build files from branch * Apply Spotless --------- Co-authored-by: jakeroseman <[email protected]> Co-authored-by: Rebecca Franks <[email protected]>
1 parent 22976bd commit e6997d9

File tree

3 files changed

+248
-1
lines changed

3 files changed

+248
-1
lines changed

compose/snippets/src/main/java/com/example/compose/snippets/SnippetsActivity.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import com.example.compose.snippets.components.MenusExamples
4646
import com.example.compose.snippets.components.PartialBottomSheet
4747
import com.example.compose.snippets.components.ProgressIndicatorExamples
4848
import com.example.compose.snippets.components.ScaffoldExample
49+
import com.example.compose.snippets.components.SearchBarExamples
4950
import com.example.compose.snippets.components.SegmentedButtonExamples
5051
import com.example.compose.snippets.components.SliderExamples
5152
import com.example.compose.snippets.components.SwitchExamples
@@ -121,6 +122,7 @@ class SnippetsActivity : ComponentActivity() {
121122
TopComponentsDestination.TooltipExamples -> TooltipExamples()
122123
TopComponentsDestination.NavigationDrawerExamples -> NavigationDrawerExamples()
123124
TopComponentsDestination.SegmentedButtonExamples -> SegmentedButtonExamples()
125+
TopComponentsDestination.SearchBarExamples -> SearchBarExamples()
124126
}
125127
}
126128
}
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
/*
2+
* Copyright 2024 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.compose.snippets.components
18+
19+
import androidx.compose.foundation.clickable
20+
import androidx.compose.foundation.layout.Arrangement
21+
import androidx.compose.foundation.layout.Box
22+
import androidx.compose.foundation.layout.Column
23+
import androidx.compose.foundation.layout.PaddingValues
24+
import androidx.compose.foundation.layout.fillMaxSize
25+
import androidx.compose.foundation.layout.fillMaxWidth
26+
import androidx.compose.foundation.layout.padding
27+
import androidx.compose.foundation.lazy.LazyColumn
28+
import androidx.compose.foundation.rememberScrollState
29+
import androidx.compose.foundation.verticalScroll
30+
import androidx.compose.material.icons.Icons
31+
import androidx.compose.material.icons.filled.MoreVert
32+
import androidx.compose.material.icons.filled.Search
33+
import androidx.compose.material.icons.filled.Star
34+
import androidx.compose.material3.Button
35+
import androidx.compose.material3.ExperimentalMaterial3Api
36+
import androidx.compose.material3.Icon
37+
import androidx.compose.material3.ListItem
38+
import androidx.compose.material3.ListItemDefaults
39+
import androidx.compose.material3.SearchBar
40+
import androidx.compose.material3.SearchBarDefaults
41+
import androidx.compose.material3.Text
42+
import androidx.compose.runtime.Composable
43+
import androidx.compose.runtime.derivedStateOf
44+
import androidx.compose.runtime.getValue
45+
import androidx.compose.runtime.mutableStateOf
46+
import androidx.compose.runtime.remember
47+
import androidx.compose.runtime.saveable.rememberSaveable
48+
import androidx.compose.runtime.setValue
49+
import androidx.compose.ui.Alignment
50+
import androidx.compose.ui.Modifier
51+
import androidx.compose.ui.graphics.Color
52+
import androidx.compose.ui.semantics.isTraversalGroup
53+
import androidx.compose.ui.semantics.semantics
54+
import androidx.compose.ui.semantics.traversalIndex
55+
import androidx.compose.ui.tooling.preview.Preview
56+
import androidx.compose.ui.unit.dp
57+
58+
@Preview
59+
@Composable
60+
fun SearchBarExamples() {
61+
Column(
62+
modifier = Modifier
63+
.padding(16.dp)
64+
.fillMaxSize(),
65+
verticalArrangement = Arrangement.spacedBy(24.dp),
66+
horizontalAlignment = Alignment.CenterHorizontally,
67+
) {
68+
var currentExample by remember { mutableStateOf<String?>(null) }
69+
70+
when (currentExample) {
71+
"basic" -> SearchBarBasicFilterList()
72+
"advanced" -> AppSearchBar()
73+
else -> {
74+
Button(onClick = { currentExample = "basic" }) {
75+
Text("Basic search bar with filter")
76+
}
77+
Button(onClick = { currentExample = "advanced" }) {
78+
Text("Advanced search bar with filter")
79+
}
80+
}
81+
}
82+
}
83+
}
84+
85+
@OptIn(ExperimentalMaterial3Api::class)
86+
// [START android_compose_components_searchbarbasicfilterlist]
87+
@Composable
88+
fun SearchBarBasicFilterList(modifier: Modifier = Modifier) {
89+
var text by rememberSaveable { mutableStateOf("") }
90+
var expanded by rememberSaveable { mutableStateOf(false) }
91+
Box(
92+
modifier
93+
.fillMaxSize()
94+
.semantics { isTraversalGroup = true }
95+
) {
96+
SearchBar(
97+
modifier = Modifier
98+
.align(Alignment.TopCenter)
99+
.semantics { traversalIndex = 0f },
100+
inputField = {
101+
SearchBarDefaults.InputField(
102+
query = text,
103+
onQueryChange = { text = it },
104+
onSearch = { expanded = false },
105+
expanded = expanded,
106+
onExpandedChange = { expanded = it },
107+
placeholder = { Text("Hinted search text") }
108+
)
109+
},
110+
expanded = expanded,
111+
onExpandedChange = { expanded = it },
112+
) {
113+
Column(Modifier.verticalScroll(rememberScrollState())) {
114+
repeat(4) { index ->
115+
val resultText = "Suggestion $index"
116+
ListItem(
117+
headlineContent = { Text(resultText) },
118+
supportingContent = { Text("Additional info") },
119+
modifier = Modifier
120+
.clickable {
121+
text = resultText
122+
expanded = false
123+
}
124+
.fillMaxWidth()
125+
)
126+
}
127+
}
128+
}
129+
}
130+
}
131+
// [END android_compose_components_searchbarbasicfilterlist]
132+
133+
@Preview(showBackground = true)
134+
@Composable
135+
private fun SearchBarBasicFilterListPreview() {
136+
SearchBarBasicFilterList()
137+
}
138+
139+
// [START android_compose_components_searchbarfilterlist]
140+
@OptIn(ExperimentalMaterial3Api::class)
141+
@Composable
142+
fun SearchBarFilterList(
143+
list: List<String>,
144+
modifier: Modifier = Modifier
145+
) {
146+
var text by rememberSaveable { mutableStateOf("") }
147+
val filteredList by remember {
148+
derivedStateOf {
149+
list.filter { it.lowercase().contains(text.lowercase()) }
150+
}
151+
}
152+
var expanded by rememberSaveable { mutableStateOf(false) }
153+
154+
Box(
155+
modifier
156+
.fillMaxSize()
157+
.semantics { isTraversalGroup = true }
158+
) {
159+
SearchBar(
160+
modifier = Modifier
161+
.align(Alignment.TopCenter)
162+
.semantics { traversalIndex = 0f },
163+
inputField = {
164+
SearchBarDefaults.InputField(
165+
query = text,
166+
onQueryChange = { text = it },
167+
onSearch = { expanded = false },
168+
expanded = expanded,
169+
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") },
173+
)
174+
},
175+
expanded = expanded,
176+
onExpandedChange = { expanded = it },
177+
) {
178+
LazyColumn {
179+
items(count = filteredList.size) { index ->
180+
val resultText = filteredList[index]
181+
ListItem(
182+
headlineContent = { Text(resultText) },
183+
supportingContent = { Text("Additional info") },
184+
leadingContent = {
185+
Icon(
186+
Icons.Filled.Star,
187+
contentDescription = "Starred item"
188+
)
189+
},
190+
colors = ListItemDefaults.colors(containerColor = Color.Transparent),
191+
modifier = Modifier
192+
.clickable {
193+
text = resultText
194+
expanded = false
195+
}
196+
.fillMaxWidth()
197+
.padding(horizontal = 16.dp, vertical = 4.dp)
198+
)
199+
}
200+
}
201+
}
202+
LazyColumn(
203+
contentPadding = PaddingValues(
204+
start = 16.dp,
205+
top = 72.dp,
206+
end = 16.dp,
207+
bottom = 16.dp
208+
),
209+
verticalArrangement = Arrangement.spacedBy(8.dp),
210+
modifier = Modifier.semantics {
211+
traversalIndex = 1f
212+
},
213+
) {
214+
items(count = filteredList.size) {
215+
Text(text = filteredList[it])
216+
}
217+
}
218+
}
219+
}
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+
}

compose/snippets/src/main/java/com/example/compose/snippets/navigation/Destination.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,6 @@ enum class TopComponentsDestination(val route: String, val title: String) {
4949
MenusExample("menusExamples", "Menus"),
5050
TooltipExamples("tooltipExamples", "Tooltips"),
5151
NavigationDrawerExamples("navigationDrawerExamples", "Navigation drawer"),
52-
SegmentedButtonExamples("segmentedButtonExamples", "Segmented button")
52+
SegmentedButtonExamples("segmentedButtonExamples", "Segmented button"),
53+
SearchBarExamples("searchBarExamples", "Search bar")
5354
}

0 commit comments

Comments
 (0)