Suchleiste

Verwenden Sie eine Suchleiste, um die Suchfunktion zu implementieren. Eine Suchleiste ist ein dauerhaft sichtbares Suchfeld, in das Nutzer ein Keyword oder eine Wortgruppe eingeben können, um relevante Ergebnisse in Ihrer App aufzurufen. Sie wird empfohlen, wenn die Suche der primäre Fokus Ihrer App ist.

Es werden zwei Suchleisten angezeigt. Das linke Feld enthält nur ein Textfeld.
  Die Suchleiste auf der linken Seite enthält ein Textfeld und darunter einen Suchvorschlag.
Abbildung 1: Eine einfache Suchleiste (1) und eine Suchleiste mit einem Vorschlag (2).

API-Oberfläche

Verwenden Sie das SearchBar-Composable, um Suchleisten zu implementieren. Die wichtigsten Parameter für diese zusammensetzbare Funktion sind:

  • inputField: Definiert das Eingabefeld der Suchleiste. Dabei wird in der Regel SearchBarDefaults.InputField verwendet, mit dem Folgendes angepasst werden kann:
    • query: Der Abfragetext, der im Eingabefeld angezeigt werden soll.
    • onQueryChange: Lambda zur Verarbeitung von Änderungen am Abfragestring.
  • expanded: Ein boolescher Wert, der angibt, ob die Suchleiste maximiert ist, um Vorschläge oder gefilterte Ergebnisse anzuzeigen.
  • onExpandedChange: Lambda zur Verarbeitung von Änderungen am erweiterten Status des Drop-down-Menüs.

  • content: Der Inhalt dieser Suchleiste, um Suchergebnisse unter der inputField anzuzeigen.

Dieses Snippet zeigt eine einfache Implementierung von SearchBar mit Vorschlägen:

@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()
                    )
                }
            }
        }
    }
}

Wichtige Punkte zum Code

  • rememberSaveable sorgt dafür, dass der Status der Suchleiste (maximiert oder minimiert) bei Konfigurationsänderungen beibehalten wird. Der gespeicherte Wert wird in das savedInstanceState-Bundle der Hosting-Aktivität geschrieben, bevor die Aktivität bei einer Konfigurationsänderung zerstört wird.
  • Der semantics-Modifikator steuert die TalkBack-Reihenfolge.
    • isTraversalGroup ist für Box festgelegt, um alle untergeordneten Composables zu gruppieren.
    • traversalIndex wird festgelegt, um die Reihenfolge anzugeben, in der TalkBack die Barrierefreiheitsinformationen der einzelnen Gruppen-Peers vorliest. TalkBack liest Informationen zur Barrierefreiheit für einen Knoten mit einem negativen Wert, z. B. -1, vor einem Knoten mit einem positiven Wert, z. B. 1, vor. Da der Wert ein Gleitkommawert ist, können Sie eine benutzerdefinierte Reihenfolge für viele Peers festlegen, indem Sie für jeden Peer Werte zwischen -1.0 und 1.0 festlegen.
  • Das SearchBar enthält ein inputField für die Nutzereingabe und ein Column zum Anzeigen von Suchvorschlägen.
    • SearchBarDefaults.InputField erstellt das Eingabefeld und verarbeitet Änderungen an der Nutzeranfrage.
    • onQueryChange verarbeitet die Texteingabe und aktualisiert den Status, wenn sich der Text im Eingabefeld ändert.
    • Der Status von The expanded steuert die Sichtbarkeit der Vorschlagsliste.
  • searchResults.forEach { result -> … } durchläuft die Liste searchResults und erstellt für jedes Ergebnis ein ListItem.
    • Wenn auf ein ListItem geklickt wird, wird das textFieldState aktualisiert, die Suchleiste wird minimiert und das textField wird mit dem ausgewählten Suchergebnis gefüllt.

Ergebnis

Eine Suchleiste mit dem Buchstaben „a“ darin. Unter der Suchleiste wird eine Liste mit sechs Suchvorschlägen angezeigt.
Abbildung 2. Eine Suchleiste mit Vorschlägen.

Suchleiste mit gefilterter Liste

In diesem Beispiel wird ein SearchBar gezeigt, mit dem eine Liste basierend auf der Suchanfrage des Nutzers gefiltert wird:

@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)
                    )
                }
            }
        }
    }
}

Wichtige Punkte zum Code

  • Die Lambda-Funktion onQueryChange wird immer dann aufgerufen, wenn der Nutzer Text in die Suchleiste eingibt oder löscht.
  • SearchBarDefaults.InputField enthält ein leadingIcon, das dem Anfang des Eingabefelds ein Suchsymbol hinzufügt, und ein trailingIcon, das dem Ende des Eingabefelds ein Symbol für „Weitere Optionen“ hinzufügt. Hier können Sie dem Nutzer Sortier- und Filteroptionen zur Verfügung stellen.
  • onSearch = { … } ruft die Lambda-Funktion onSearch auf und minimiert die Suchleiste, wenn die Suche gesendet wird.
  • Ein LazyColumn verarbeitet eine potenziell große Anzahl von Suchergebnissen effizient. Die Liste searchResults wird durchlaufen und jedes Ergebnis als ListItem angezeigt.
  • Jede ListItem-Composable-Funktion zeigt den Artikeltext, Text mit zusätzlichen Informationen und ein Sternsymbol als leadingContent des Artikels. In diesem Beispiel wird eine Option zum Favorisieren des Artikels angezeigt.
  • Die Filterlogik finden Sie unter CustomizableSearchBarExample im vollständigen Quellcode auf GitHub.

Ergebnis

Eine Suchleiste mit dem Hinweis „Textsuche“ wird angezeigt. Unterhalb der Suchleiste wird eine Liste mit Suchvorschlägen angezeigt. Neben jedem Vorschlag befindet sich ein Sternsymbol.
Abbildung 3: Eine Suchleiste mit relevanten Vorschlägen wird angezeigt.

Zusätzliche Ressourcen