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

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

Отображаются две панели поиска. Тот, что слева, имеет только текстовое поле.   Панель поиска слева имеет текстовое поле и подсказку для поиска под ним.
Рисунок 1. Базовая панель поиска (1) и панель поиска с подсказкой (2).

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

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

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

  • 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 выбранным результатом поиска.

Результат

Панель поиска отображается с буквой «а», напечатанной внутри нее. Под строкой поиска отображается список, содержащий шесть поисковых предложений.
Рисунок 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. Панель поиска с соответствующими предложениями.

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