Barre de recherche

Utilisez une barre de recherche pour implémenter la fonctionnalité de recherche. Une barre de recherche est un champ de recherche persistant qui permet aux utilisateurs de saisir un mot clé ou une expression pour afficher des résultats pertinents dans votre application. Elle est recommandée lorsque la recherche est l'objectif principal de votre application.

Deux barres de recherche s'affichent. Celle de gauche ne comporte qu'un champ de texte.
  La barre de recherche située à gauche comporte un champ de texte et une suggestion de recherche en dessous.
Figure 1. Barre de recherche de base (1) et barre de recherche avec suggestion (2).

Surface de l'API

Utilisez le composable SearchBar pour implémenter des barres de recherche. Voici les principaux paramètres de ce composable:

  • inputField: définit le champ de saisie de la barre de recherche. Il utilise généralement SearchBarDefaults.InputField, qui permet de personnaliser les éléments suivants :
    • query: texte de la requête à afficher dans le champ de saisie.
    • onQueryChange: Lambda pour gérer les modifications apportées à la chaîne de requête.
  • expanded: valeur booléenne indiquant si la barre de recherche est développée pour afficher des suggestions ou des résultats filtrés.
  • onExpandedChange: Lambda pour gérer les modifications de l'état développé du menu déroulant.

  • content: contenu de cette barre de recherche pour afficher les résultats de recherche sous inputField.

Cet extrait montre une implémentation de base de SearchBar avec des suggestions:

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

Points clés concernant le code

  • rememberSaveable garantit que l'état de la barre de recherche (développée ou réduite) est conservé lors des modifications de configuration. Il écrit la valeur mémorisée dans le bundle savedInstanceState de l'activité hôte avant que l'activité ne soit détruite lors d'une modification de configuration.
  • Le modificateur semantics contrôle l'ordre de balayage de TalkBack.
    • isTraversalGroup est défini pour que Box regroupe tous ses composables enfants.
    • traversalIndex est défini pour spécifier l'ordre dans lequel TalkBack lit les informations d'accessibilité de chaque paire de groupe. TalkBack lit les informations d'accessibilité sur un pair avec une valeur négative, telle que -1, avant un pair avec une valeur positive, telle que 1. Étant donné que la valeur est une valeur flottante, vous pouvez spécifier un ordre personnalisé de nombreux pairs en définissant des valeurs comprises entre -1.0 et 1.0 sur chaque pair.
  • SearchBar contient un inputField pour la saisie utilisateur et un Column pour afficher des suggestions de recherche.
    • SearchBarDefaults.InputField crée le champ de saisie et gère les modifications apportées à la requête utilisateur.
    • onQueryChange gère la saisie de texte et met à jour l'état chaque fois que le texte du champ de saisie change.
    • L'état The expanded contrôle la visibilité de la liste de suggestions.
  • searchResults.forEach { result -> … } itère sur la liste searchResults et crée un ListItem pour chaque résultat.
    • Lorsqu'un utilisateur clique sur un ListItem, le textFieldState est mis à jour, la barre de recherche est réduite et le textField est rempli avec le résultat de recherche sélectionné.

Résultat

Une barre de recherche s&#39;affiche avec la lettre &quot;a&quot; saisie dans la barre. Une liste contenant six suggestions de recherche s&#39;affiche sous la barre de recherche.
Figure 2. Barre de recherche avec des suggestions affichées.

Barre de recherche avec liste filtrée

Cet exemple montre un SearchBar qui filtre une liste en fonction de la requête de recherche de l'utilisateur:

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

Points clés concernant le code

  • La fonction lambda onQueryChange est appelée chaque fois que l'utilisateur saisit ou supprime du texte dans la barre de recherche.
  • SearchBarDefaults.InputField contient un leadingIcon, qui ajoute une icône de recherche au début du champ de saisie, et un trailingIcon, qui ajoute une icône "Plus d'options" à la fin du champ de saisie. Vous pouvez y fournir des options de tri et de filtrage à l'utilisateur.
  • onSearch = { … } appelle le lambda onSearch et réduit la barre de recherche lorsque la recherche est envoyée.
  • Un LazyColumn gère efficacement un grand nombre potentiel de résultats de recherche. Il parcourt la liste searchResults et affiche chaque résultat sous forme de ListItem.
  • Chaque composable ListItem affiche le texte de l'élément, un texte contenant des informations supplémentaires et une icône en forme d'étoile comme leadingContent de l'élément. Dans cet exemple, une option permettant d'ajouter l'élément aux favoris est proposée.
  • Pour la logique de filtrage, consultez CustomizableSearchBarExample dans le code source complet sur GitHub.

Résultat

Une barre de recherche contenant les mots &quot;recherche de texte suggérée&quot; s&#39;affiche. Sous la barre de recherche, une liste de suggestions de recherche s&#39;affiche, avec une icône en forme d&#39;étoile à côté de chaque suggestion.
Figure 3. Barre de recherche avec des suggestions pertinentes affichées.

Ressources supplémentaires