Pasek wyszukiwania

Aby wdrożyć funkcję wyszukiwania, użyj paska wyszukiwania. Pasek wyszukiwania to stałe pole wyszukiwania, które umożliwia użytkownikom wpisanie słowa kluczowego lub wyrażenia w celu wyświetlenia odpowiednich wyników w aplikacji. Jest on zalecany, gdy wyszukiwanie jest główną funkcją aplikacji.

Wyświetlają się 2 paski wyszukiwania. Ten po lewej stronie ma tylko pole tekstowe.
  Pasek wyszukiwania po prawej stronie zawiera pole tekstowe i sugestię wyszukiwania pod nim.
Rysunek 1. Podstawowy pasek wyszukiwania (1) i pasek wyszukiwania z sugestią (2).

Interfejs API

Aby zaimplementować paski wyszukiwania, użyj funkcji kompozycyjnej SearchBar. Najważniejsze parametry tego elementu kompozycyjnego:

  • inputField: definiuje pole do wprowadzania danych na pasku wyszukiwania. Zwykle wykorzystuje SearchBarDefaults.InputField, co umożliwia dostosowanie:
    • query: tekst zapytania, który ma być wyświetlany w polu do wprowadzania danych.
    • onQueryChange: funkcja lambda do obsługi zmian w ciągu zapytania.
  • expanded: wartość logiczna wskazująca, czy pasek wyszukiwania jest rozwinięty, aby wyświetlać sugestie lub odfiltrowane wyniki.
  • onExpandedChange: lambda do obsługi zmian w rozwiniętym stanie menu.

  • content: zawartość tego paska wyszukiwania, aby wyświetlić wyniki wyszukiwania poniżej inputField.

Ten fragment kodu pokazuje podstawową implementację SearchBar z sugestiami:

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

Najważniejsze informacje o kodzie

  • rememberSaveable zapewnia, że stan paska wyszukiwania (rozwinięty lub zwinięty) jest zachowywany podczas zmian konfiguracji. Zapisuje zapamiętaną wartość w pakiecie savedInstanceState aktywności hostującej, zanim aktywność zostanie zniszczona podczas zmiany konfiguracji.
  • Modyfikator semantics kontroluje kolejność przechodzenia między elementami w TalkBack.
    • Wartość isTraversalGroup jest ustawiona dla Box, aby grupować wszystkie elementy kompozycyjne podrzędne.
    • Atrybut traversalIndex określa kolejność, w jakiej TalkBack odczytuje informacje o ułatwieniach dostępu z każdego elementu grupy. TalkBack odczytuje informacje o ułatwieniach dostępu w przypadku elementu o wartości ujemnej, np. -1, przed elementem o wartości dodatniej, np. 1. Wartość jest liczbą zmiennoprzecinkową, więc możesz określić niestandardową kolejność wielu elementów równorzędnych, ustawiając wartości między -1.0 a 1.0 dla każdego z nich.
  • Komponent SearchBar zawiera element inputField do wprowadzania danych przez użytkownika i element Column do wyświetlania sugestii wyszukiwania.
    • SearchBarDefaults.InputField tworzy pole do wprowadzania danych i obsługuje zmiany w zapytaniu użytkownika.
    • onQueryChange obsługuje wprowadzanie tekstu i aktualizuje stan za każdym razem, gdy tekst w polu do wprowadzania danych ulega zmianie.
    • Stan expanded określa widoczność listy sugestii.
  • searchResults.forEach { result -> … } wykonuje iterację listy searchResults i tworzy ListItem dla każdego wyniku.
    • Kliknięcie elementu ListItem powoduje zaktualizowanie elementu textFieldState, zwinięcie paska wyszukiwania i wypełnienie elementu textField wybranym wynikiem wyszukiwania.

Wynik

Pasek wyszukiwania z wpisaną literą „a”. Pod paskiem wyszukiwania wyświetla się lista zawierająca 6 sugestii wyszukiwania.
Rysunek 2. Pasek wyszukiwania z wyświetlonymi sugestiami.

Pasek wyszukiwania z przefiltrowaną listą

Ten przykład pokazuje element SearchBar, który filtruje listę na podstawie zapytania użytkownika:

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

Najważniejsze informacje o kodzie

  • Funkcja lambda onQueryChange jest wywoływana za każdym razem, gdy użytkownik wpisze lub usunie tekst na pasku wyszukiwania.
  • SearchBarDefaults.InputField zawiera leadingIcon, który dodaje ikonę wyszukiwania na początku pola do wprowadzania danych, oraz trailingIcon, który dodaje ikonę „więcej opcji” na końcu pola do wprowadzania danych. Tutaj możesz udostępnić użytkownikowi opcje sortowania i filtrowania.
  • onSearch = { … } wywołuje funkcję lambda onSearch i zwija pasek wyszukiwania po przesłaniu wyszukiwania.
  • LazyColumn skutecznie obsługuje potencjalnie dużą liczbę wyników wyszukiwania. Iteruje listę searchResults i wyświetla każdy wynik jako ListItem.
  • Każdy element kompozycyjny ListItem wyświetla tekst elementu, tekst z dodatkowymi informacjami i ikonę gwiazdki jako leadingContent elementu. W tym przykładzie wyświetlana jest opcja dodania produktu do ulubionych.
  • Logikę filtrowania znajdziesz w funkcji CustomizableSearchBarExample w pełnym kodzie źródłowym na GitHubie.

Wynik

Wyświetla się pasek wyszukiwania z tekstem „Wyszukaj tekst”. Pod paskiem wyszukiwania wyświetla się lista sugestii wyszukiwania, a obok każdej z nich znajduje się ikona gwiazdki.
Rysunek 3. Pasek wyszukiwania z wyświetlonymi odpowiednimi sugestiami.

Dodatkowe materiały