Barra di ricerca

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

Vengono visualizzate due barre di ricerca. Quello a sinistra ha solo un campo di testo.
  La barra di ricerca a sinistra ha 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).

Superficie API

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

  • inputField: definisce il campo di input della barra di ricerca. In genere utilizza SearchBarDefaults.InputField, che consente la personalizzazione di:
    • query: il testo della query da mostrare nel campo di input.
    • 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 nello stato espanso del menu a discesa.

  • content: il contenuto 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 (espansa o compressa) venga mantenuto durante le modifiche alla configurazione. Scrive il valore memorizzato nel bundle savedInstanceState dell'attività di hosting prima che l'attività venga eliminata durante una modifica della configurazione.
  • Il modificatore semantics controlla l'ordine di attraversamento di TalkBack.
    • isTraversalGroup è impostato per Box per raggruppare tutti i relativi componenti componibili secondari.
    • traversalIndex è impostato per specificare l'ordine in cui TalkBack legge le informazioni sull'accessibilità di ogni peer del gruppo. TalkBack legge le informazioni sull'accessibilità di 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.
  • Il SearchBar contiene un inputField per l'input dell'utente e un Column per visualizzare i suggerimenti di ricerca.
    • SearchBarDefaults.InputField crea il campo di input 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 input cambia.
    • Lo stato di The expanded controlla la visibilità dell'elenco dei suggerimenti.
  • searchResults.forEach { result -> … } scorre l'elenco searchResults e crea un ListItem per ogni risultato.
    • Quando si fa clic su un ListItem, viene aggiornato il textFieldState, la barra di ricerca viene compressa e il textField viene compilato con il risultato di ricerca selezionato.

Risultato

Viene mostrata una barra di ricerca con la lettera &quot;a&quot; digitata all&#39;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 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 opzioni di ordinamento e filtro all'utente.
  • onSearch = { … } chiama la 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. Itera l'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 visualizzata un'opzione per aggiungere l'elemento ai preferiti.
  • Per la logica di filtraggio, consulta CustomizableSearchBarExample nel codice sorgente completo su GitHub.

Risultato

Viene visualizzata una barra di ricerca contenente le parole Ricerca di testo suggerita all&#39;interno. 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