Панель поиска

Используйте строку поиска для реализации функции поиска. Строка поиска — это постоянное поле поиска, позволяющее пользователям вводить ключевое слово или фразу для отображения релевантных результатов в вашем приложении. Рекомендуется использовать её, когда поиск является основной задачей вашего приложения.

Показаны две строки поиска. В левой строке есть только текстовое поле. В левой строке поиска есть текстовое поле и подсказка поиска.
Рисунок 1. Базовая строка поиска (1) и строка поиска с подсказкой (2).

API поверхность

Используйте компонуемый объект SearchBar для реализации панелей поиска. Ключевые параметры этого компонуемого объекта включают в себя:

  • inputField : определяет поле ввода строки поиска. Обычно используется SearchBarDefaults.InputField , которое позволяет настраивать:
    • query : Текст запроса, который будет отображен в поле ввода.
    • onQueryChange : Лямбда-функция для обработки изменений в строке запроса.
  • expanded : логическое значение, указывающее, расширена ли строка поиска для отображения предложений или отфильтрованных результатов.
  • onExpandedChange : лямбда-функция для обработки изменений в развернутом состоянии раскрывающегося списка.

  • content : Содержимое этой строки поиска для отображения результатов поиска под полем inputField .

В этом фрагменте показана базовая реализация SearchBar с предложениями:

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

Ключевые моменты кода

  • rememberSaveable гарантирует сохранение состояния строки поиска (развёрнутой или свёрнутой) при изменении конфигурации. Она записывает запомненное значение в пакет savedInstanceState хост-активности до того, как активность будет уничтожена при изменении конфигурации.
  • Модификатор semantics управляет порядком обхода TalkBack.
    • isTraversalGroup настроен на группировку всех дочерних составных элементов Box .
    • traversalIndex задаёт порядок, в котором TalkBack считывает информацию о доступности с каждого однорангового узла группы. TalkBack считывает информацию о доступности с однорангового узла с отрицательным значением, например, -1 , прежде чем с однорангового узла с положительным значением, например, 1 Поскольку значение является числом с плавающей точкой, можно задать произвольный порядок для нескольких одноранговых узлов, установив значения в диапазоне от -1.0 до 1.0 для каждого однорангового узла.
  • SearchBar содержит inputField для ввода данных пользователем и Column для отображения поисковых предложений.
    • SearchBarDefaults.InputField создает поле ввода и обрабатывает изменения пользовательского запроса.
    • onQueryChange обрабатывает ввод текста и обновляет состояние при каждом изменении текста в поле ввода.
    • The expanded состояние управляет видимостью списка предложений.
  • searchResults.forEach { result -> … } перебирает список searchResults и создает ListItem для каждого результата.
    • При щелчке по элементу ListItem обновляется textFieldState , сворачивается строка поиска и заполняется textField выбранным результатом поиска.

Результат

На экране отображается строка поиска с напечатанной буквой «a». Под строкой поиска отображается список из шести вариантов поиска.
Рисунок 2. Панель поиска с отображаемыми предложениями.

Панель поиска с отфильтрованным списком

В этом примере показана SearchBar , которая фильтрует список на основе поискового запроса пользователя:

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

Ключевые моменты кода

  • Лямбда-функция onQueryChange вызывается всякий раз, когда пользователь вводит или удаляет текст в строке поиска.
  • SearchBarDefaults.InputField содержит leadingIcon , добавляющий значок поиска в начало поля ввода, и trailingIcon , добавляющий значок «Дополнительные параметры» в конец поля ввода. Здесь вы можете предоставить пользователю возможности сортировки и фильтрации.
  • onSearch = { … } вызывает лямбда- onSearch и сворачивает панель поиска при отправке поиска.
  • LazyColumn эффективно обрабатывает потенциально большое количество результатов поиска. Он просматривает список searchResults и отображает каждый результат как ListItem .
  • Каждый компонуемый ListItem отображает текст элемента, текст с дополнительной информацией и значок звёздочки в качестве leadingContent элемента. В этом примере представлена возможность добавить элемент в избранное.
  • Логику фильтрации см. в разделе CustomizableSearchBarExample в полном исходном коде на GitHub .

Результат

Отображается строка поиска, содержащая подсказки по поисковому запросу. Под строкой поиска отображается список поисковых предложений со значком звёздочки рядом с каждым предложением.
Рисунок 3. Панель поиска с отображаемыми соответствующими предложениями.

Дополнительные ресурсы