Suchleiste

Verwenden Sie eine Suchleiste, um die Suchfunktion zu implementieren. Eine Suchleiste ist ein dauerhaftes Suchfeld, in das Nutzer ein Keyword oder eine Wortgruppe eingeben können, um relevante Ergebnisse in Ihrer App anzuzeigen. Sie wird empfohlen, wenn die Suche der Hauptfokus Ihrer App ist.

Es werden zwei Suchleisten angezeigt. Die linke hat nur ein Textfeld.
  Die Suchleiste auf der rechten Seite hat 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 Compose-Element SearchBar, um Suchleisten zu implementieren. Zu den wichtigsten Parametern für diese komponierbare Funktion gehören:

  • inputField: Definiert das Eingabefeld der Suchleiste. In der Regel wird SearchBarDefaults.InputField verwendet, womit Folgendes angepasst werden kann:
    • query: Der Abfragetext, der im Eingabefeld angezeigt werden soll.
    • onQueryChange: Lambda-Funktion zum Verarbeiten von Änderungen im 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 maximierten Zustand 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 während einer Konfigurationsänderung gelöscht wird.
  • Der Modifikator semantics steuert die TalkBack-Durchlaufreihenfolge.
    • isTraversalGroup ist für Box festgelegt, um alle untergeordneten Composables zu gruppieren.
    • traversalIndex wird festgelegt, um die Reihenfolge anzugeben, in der TalkBack Informationen zur Barrierefreiheit von jedem Gruppen-Peer liest. TalkBack liest Informationen zur Barrierefreiheit für ein gleichgeordnetes Element mit einem negativen Wert, z. B. -1, vor einem gleichgeordneten Element mit einem positiven Wert, z. B. 1. Da der Wert ein Gleitkommawert ist, können Sie eine benutzerdefinierte Reihenfolge für viele Peers angeben, indem Sie für jeden Peer Werte zwischen -1.0 und 1.0 festlegen.
  • Die SearchBar enthält ein inputField für Nutzereingaben und eine Column zum Anzeigen von Suchvorschlägen.
    • SearchBarDefaults.InputField erstellt das Eingabefeld und verarbeitet Änderungen an der Nutzerabfrage.
    • onQueryChange verarbeitet die Texteingabe und aktualisiert den Status, wenn sich der Text im Eingabefeld ändert.
    • Der Status expanded steuert die Sichtbarkeit der Vorschlagsliste.
  • searchResults.forEach { result -> … } iteriert durch die Liste searchResults und erstellt für jedes Ergebnis ein ListItem.
    • Wenn ein ListItem angeklickt wird, wird der textFieldState aktualisiert, die Suchleiste minimiert und das textField mit dem ausgewählten Suchergebnis gefüllt.

Ergebnis

Eine Suchleiste wird angezeigt, in die der Buchstabe „a“ eingegeben wurde. 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, das eine Liste anhand der Suchanfrage des Nutzers filtert:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CustomizableSearchBar(
    query: String,
    onQueryChange: (String) -> Unit,
    onSearch: (String) -> Unit,
    searchResults: List<String>,
    onResultClick: (String) -> Unit,
    modifier: Modifier = Modifier,
    // 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,
) {
    // 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 daraus löscht.
  • SearchBarDefaults.InputField enthält ein leadingIcon, das am Anfang des Eingabefelds ein Suchsymbol hinzufügt, und ein trailingIcon, das am Ende des Eingabefelds ein Symbol für „Weitere Optionen“ hinzufügt. Hier können Sie den Nutzenden Sortier- und Filteroptionen anbieten.
  • onSearch = { … } ruft den Lambda-Ausdruck 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 wird als ListItem angezeigt.
  • Jedes ListItem-Composable zeigt den Elementtext, Text mit zusätzlichen Informationen und ein Sternsymbol als leadingContent des Elements an. 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 Text „Textsuche“ wird angezeigt. Unter der Suchleiste wird eine Liste mit Suchvorschlägen angezeigt. Neben jedem Vorschlag befindet sich ein Sternsymbol.
Abbildung 3: Eine Suchleiste mit relevanten Vorschlägen.

Zusätzliche Ressourcen