Barra di ricerca

Utilizza una barra di ricerca per implementare la funzionalità di ricerca. Una barra di ricerca è un campo di ricerca permanente che consente agli utenti di inserire una parola chiave o una frase per visualizzare risultati pertinenti all'interno della tua app ed è consigliata quando la ricerca è l'obiettivo principale della tua app.

Vengono visualizzate due barre di ricerca. Quello a sinistra ha solo un campo di testo.
  La barra di ricerca a sinistra contiene un campo di testo e un suggerimento di ricerca sotto.
Figura 1. Una barra di ricerca di base (1) e una barra di ricerca con un suggerimento (2).

API surface

Utilizza il composable SearchBar per implementare le barre di ricerca. I parametri chiave per questo composable includono:

  • inputField: definisce il campo di immissione della barra di ricerca. In genere utilizza SearchBarDefaults.InputField, che consente di personalizzare:
    • query: il testo della query da mostrare nel campo di immissione.
    • onQueryChange: Lambda per gestire le modifiche nella stringa di query.
  • expanded: un valore booleano che indica se la barra di ricerca è espansa per mostrare suggerimenti o risultati filtrati.
  • onExpandedChange: Lambda per gestire le modifiche allo stato espanso del menu a discesa.

  • content: i contenuti di questa barra di ricerca per visualizzare i risultati di ricerca sotto inputField.

Questo snippet mostra un'implementazione di base di SearchBar con suggerimenti:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SimpleSearchBar(
    textFieldState: TextFieldState,
    onSearch: (String) -> Unit,
    searchResults: List<String>,
    modifier: Modifier = Modifier
) {
    // Controls expansion state of the search bar
    var expanded by rememberSaveable { mutableStateOf(false) }

    Box(
        modifier
            .fillMaxSize()
            .semantics { isTraversalGroup = true }
    ) {
        SearchBar(
            modifier = Modifier
                .align(Alignment.TopCenter)
                .semantics { traversalIndex = 0f },
            inputField = {
                SearchBarDefaults.InputField(
                    query = textFieldState.text.toString(),
                    onQueryChange = { textFieldState.edit { replace(0, length, it) } },
                    onSearch = {
                        onSearch(textFieldState.text.toString())
                        expanded = false
                    },
                    expanded = expanded,
                    onExpandedChange = { expanded = it },
                    placeholder = { Text("Search") }
                )
            },
            expanded = expanded,
            onExpandedChange = { expanded = it },
        ) {
            // Display search results in a scrollable column
            Column(Modifier.verticalScroll(rememberScrollState())) {
                searchResults.forEach { result ->
                    ListItem(
                        headlineContent = { Text(result) },
                        modifier = Modifier
                            .clickable {
                                textFieldState.edit { replace(0, length, result) }
                                expanded = false
                            }
                            .fillMaxWidth()
                    )
                }
            }
        }
    }
}

Punti chiave del codice

  • rememberSaveable garantisce che lo stato della barra di ricerca (se espansa o chiusa) venga mantenuto invariato durante le modifiche alla configurazione. Scrive il valore memorizzato nel bundle savedInstanceState dell'attività ospitante prima che l'attività venga distrutta durante una modifica della configurazione.
  • Il modificatore semantics controlla l'ordine di esplorazione di TalkBack.
    • isTraversalGroup è impostato per Box in modo da raggruppare tutti i relativi composabili secondari.
    • traversalIndex è impostato per specificare l'ordine in cui TalkBack legge le informazioni sull'accessibilità di ciascun peer del gruppo. TalkBack legge le informazioni sull'accessibilità su un peer con un valore negativo, ad esempio -1, prima di un peer con un valore positivo, ad esempio 1. Poiché il valore è un numero in virgola mobile, puoi specificare un ordine personalizzato di molti peer impostando valori compresi tra -1.0 e 1.0 su ciascun peer.
  • SearchBar contiene un inputField per l'input dell'utente e un Column per visualizzare i suggerimenti di ricerca.
    • SearchBarDefaults.InputField crea il campo di immissione e gestisce le modifiche alla query dell'utente.
    • onQueryChange gestisce l'input di testo e aggiorna lo stato ogni volta che il testo nel campo di immissione cambia.
    • Lo stato The expanded controlla la visibilità dell'elenco di suggerimenti.
  • searchResults.forEach { result -> … } esegue l'iterazione dell'elenco searchResults e crea un ListItem per ogni risultato.
    • Quando si fa clic su un ListItem, viene aggiornato il textFieldState, si comprime la barra di ricerca e si compila il textField con il risultato di ricerca selezionato.

Risultato

Viene visualizzata una barra di ricerca con la lettera &quot;a&quot; digitata al suo interno. Sotto la barra di ricerca viene visualizzato un elenco contenente sei suggerimenti di ricerca.
Figura 2. Una barra di ricerca con i suggerimenti visualizzati.

Barra di ricerca con elenco filtrato

Questo esempio mostra un SearchBar che filtra un elenco in base alla query di ricerca dell'utente:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CustomizableSearchBar(
    query: String,
    onQueryChange: (String) -> Unit,
    onSearch: (String) -> Unit,
    searchResults: List<String>,
    onResultClick: (String) -> Unit,
    // Customization options
    placeholder: @Composable () -> Unit = { Text("Search") },
    leadingIcon: @Composable (() -> Unit)? = { Icon(Icons.Default.Search, contentDescription = "Search") },
    trailingIcon: @Composable (() -> Unit)? = null,
    supportingContent: (@Composable (String) -> Unit)? = null,
    leadingContent: (@Composable () -> Unit)? = null,
    modifier: Modifier = Modifier
) {
    // Track expanded state of search bar
    var expanded by rememberSaveable { mutableStateOf(false) }

    Box(
        modifier
            .fillMaxSize()
            .semantics { isTraversalGroup = true }
    ) {
        SearchBar(
            modifier = Modifier
                .align(Alignment.TopCenter)
                .semantics { traversalIndex = 0f },
            inputField = {
                // Customizable input field implementation
                SearchBarDefaults.InputField(
                    query = query,
                    onQueryChange = onQueryChange,
                    onSearch = {
                        onSearch(query)
                        expanded = false
                    },
                    expanded = expanded,
                    onExpandedChange = { expanded = it },
                    placeholder = placeholder,
                    leadingIcon = leadingIcon,
                    trailingIcon = trailingIcon
                )
            },
            expanded = expanded,
            onExpandedChange = { expanded = it },
        ) {
            // Show search results in a lazy column for better performance
            LazyColumn {
                items(count = searchResults.size) { index ->
                    val resultText = searchResults[index]
                    ListItem(
                        headlineContent = { Text(resultText) },
                        supportingContent = supportingContent?.let { { it(resultText) } },
                        leadingContent = leadingContent,
                        colors = ListItemDefaults.colors(containerColor = Color.Transparent),
                        modifier = Modifier
                            .clickable {
                                onResultClick(resultText)
                                expanded = false
                            }
                            .fillMaxWidth()
                            .padding(horizontal = 16.dp, vertical = 4.dp)
                    )
                }
            }
        }
    }
}

Punti chiave del codice

  • La funzione lambda onQueryChange viene chiamata ogni volta che l'utente digita o elimina del testo nella barra di ricerca.
  • SearchBarDefaults.InputField contiene un leadingIcon, che aggiunge un'icona di ricerca all'inizio del campo di immissione, e un trailingIcon, che aggiunge un'icona "Altre opzioni" alla fine del campo di immissione. Qui puoi fornire all'utente opzioni di ordinamento e filtro.
  • onSearch = { … } chiama la funzione lambda onSearch e comprime la barra di ricerca quando viene inviata la ricerca.
  • Un LazyColumn gestisce in modo efficiente un numero potenzialmente elevato di risultati di ricerca. Esegue l'iterazione dell'elenco searchResults e mostra ogni risultato come ListItem.
  • Ogni composable ListItem mostra il testo dell'elemento, il testo che mostra informazioni aggiuntive e un'icona a forma di stella come leadingContent dell'elemento. In questo esempio, viene presentata un'opzione per aggiungere l'articolo ai preferiti.
  • Per la logica di filtro, consulta CustomizableSearchBarExample nel codice sorgente completo su GitHub.

Risultato

Viene visualizzata una barra di ricerca contenente le parole di ricerca di testo suggerite. Sotto la barra di ricerca viene visualizzato un elenco di suggerimenti di ricerca, con un&#39;icona a forma di stella accanto a ogni suggerimento.
Figura 3. Una barra di ricerca con suggerimenti pertinenti visualizzati.

Risorse aggiuntive