Barra de pesquisa

Use uma barra de pesquisa para implementar a funcionalidade de pesquisa. Uma barra de pesquisa é um campo de pesquisa persistente que permite que os usuários insiram uma palavra-chave ou frase para mostrar resultados relevantes no app. Ela é recomendada quando a pesquisa é o foco principal do app.

Duas barras de pesquisa são mostradas. O da esquerda tem apenas um campo de texto.
  A barra de pesquisa à esquerda tem um campo de texto e uma sugestão de pesquisa abaixo.
Figura 1. Uma barra de pesquisa básica (1) e uma barra de pesquisa com uma sugestão (2).

Superfície da API

Use o elemento combinável SearchBar para implementar barras de pesquisa. Os principais parâmetros para esse elemento combinável incluem:

  • inputField: define o campo de entrada da barra de pesquisa. Ele geralmente usa SearchBarDefaults.InputField, que permite a personalização de:
    • query: o texto da consulta que será mostrado no campo de entrada.
    • onQueryChange: Lambda para processar mudanças na string de consulta.
  • expanded: um booleano que indica se a barra de pesquisa está aberta para mostrar sugestão ou resultados filtrados.
  • onExpandedChange: Lambda para processar mudanças no estado aberto do menu suspenso.

  • content: o conteúdo dessa barra de pesquisa para mostrar os resultados da pesquisa abaixo do inputField.

Este snippet mostra uma implementação básica de SearchBar com sugestões:

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

Pontos principais sobre o código

  • O rememberSaveable garante que a barra de pesquisa seja expandida ou recolhida durante as mudanças de configuração. Ele grava o valor lembrado no pacote savedInstanceState da atividade de hospedagem antes que a atividade seja destruída durante uma mudança de configuração.
  • O modificador semantics controla a ordem de travessia do TalkBack.
    • isTraversalGroup é definido para Box agrupar todos os elementos combináveis filhos.
    • traversalIndex é definido para especificar a ordem em que o TalkBack lê informações de acessibilidade de cada peer do grupo. O TalkBack lê informações de acessibilidade em um peer com um valor negativo, como -1, antes de um peer com um valor positivo, como 1. Como o valor é flutuante, é possível especificar uma ordem personalizada de muitos pares definindo valores entre -1.0 e 1.0 em cada par.
  • O SearchBar contém um inputField para entrada do usuário e um Column para mostrar sugestões de pesquisa.
    • SearchBarDefaults.InputField cria o campo de entrada e processa as mudanças na consulta do usuário.
    • O onQueryChange processa a entrada de texto e atualiza o estado sempre que o texto no campo de entrada muda.
    • O estado The expanded controla a visibilidade da lista de sugestões.
  • searchResults.forEach { result -> … } itera pela lista searchResults e cria um ListItem para cada resultado.
    • Quando um ListItem é clicado, ele atualiza o textFieldState, reduz a barra de pesquisa e preenche o textField com o resultado de pesquisa selecionado.

Resultado

Uma barra de pesquisa é mostrada com a letra &quot;a&quot; digitada dentro dela. Uma lista com seis sugestões de pesquisa é exibida abaixo da barra de pesquisa.
Figura 2. Uma barra de pesquisa com sugestões exibidas.

Barra de pesquisa com lista filtrada

Este exemplo mostra um SearchBar que filtra uma lista com base na consulta de pesquisa do usuário:

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

Pontos principais sobre o código

  • A função lambda onQueryChange é chamada sempre que o usuário digita ou apaga texto na barra de pesquisa.
  • SearchBarDefaults.InputField contém um leadingIcon, que adiciona um ícone de pesquisa ao início do campo de entrada, e um trailingIcon, que adiciona um ícone "mais opções" ao final do campo de entrada. Aqui, você pode oferecer opções de classificação e filtragem ao usuário.
  • onSearch = { … } chama a lambda onSearch e oculta a barra de pesquisa quando a pesquisa é enviada.
  • Um LazyColumn processa um número potencialmente grande de resultados de pesquisa de maneira eficiente. Ele itera a lista searchResults e mostra cada resultado como um ListItem.
  • Cada elemento combinável ListItem mostra o texto do item, o texto mostrando informações adicionais e um ícone de estrela como o leadingContent do item. Neste exemplo, uma opção para adicionar o item aos favoritos é apresentada.
  • Para a lógica de filtragem, consulte CustomizableSearchBarExample no código-fonte completo no GitHub.

Resultado

Uma barra de pesquisa com as palavras &quot;hinted text search&quot; é mostrada. Abaixo da barra de pesquisa, uma lista de sugestões de pesquisa é exibida, com um ícone de estrela ao lado de cada sugestão.
Figura 3. Uma barra de pesquisa com sugestões relevantes exibidas.

Outros recursos