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

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

Показаны две строки поиска. Левая содержит только текстовое поле. Левая строка поиска содержит текстовое поле и подсказку для поиска под ним.
Рисунок 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 заполняется выбранным результатом поиска.

Результат

Отображается строка поиска, в которую вводится буква «а». Под строкой поиска отображается список из шести поисковых подсказок.
Рисунок 2. Поисковая строка с отображаемыми подсказками.

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

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

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

Основные моменты, касающиеся кода.

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

Результат

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

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