Configurer les champs de texte

TextField permet aux utilisateurs de saisir et de modifier du texte. Vous pouvez utiliser deux types de champs de texte : les champs de texte basés sur l'état et les champs de texte basés sur la valeur. Sélectionnez le type de contenu pour lequel vous souhaitez afficher les résultats :

Nous vous recommandons d'utiliser des champs de texte basés sur l'état, car ils offrent une approche plus complète et fiable pour gérer l'état d'un TextField. Le tableau suivant décrit les différences entre ces types de champs de texte et présente les principaux avantages des champs de texte basés sur l'état :

Fonctionnalité

Champs de texte basés sur la valeur

Champs de texte basés sur l'état

Avantage basé sur l'état

Gestion de l'état

Met à jour l'état du champ de texte avec le rappel onValueChange. Il vous incombe de mettre à jour le value dans votre propre état en fonction des modifications signalées par onValueChange.

Utilise explicitement un objet TextFieldState pour gérer l'état de la saisie de texte (valeur, sélection, composition). Cet état peut être mémorisé et partagé.

  • Le rappel onValueChange a été supprimé, ce qui vous empêche d'introduire des comportements asynchrones.
  • L'état survit à la recomposition, à la configuration et à l'arrêt du processus.

Transformation visuelle

Utilise VisualTransformation pour modifier l'apparence du texte affiché. Cela gère généralement la mise en forme des entrées et des sorties en une seule étape.

Utilise InputTransformation pour modifier la saisie de l'utilisateur avant qu'elle ne soit enregistrée dans l'état et OutputTransformation pour mettre en forme le contenu du champ de texte sans modifier les données d'état sous-jacentes.

  • Vous n'avez plus besoin de fournir le mappage de décalage entre le texte brut d'origine et le texte transformé avec OutputTransformation.

Limites de lignes

Accepte singleLine: Boolean, maxLines: Int et minLines: Int pour contrôler le nombre de lignes.

Utilise lineLimits: TextFieldLineLimits pour configurer le nombre minimal et maximal de lignes que le champ de texte peut occuper.

  • Supprime l'ambiguïté lors de la configuration des limites de lignes en fournissant un paramètre lineLimits de type TextFieldLineLimits.

Champ de texte sécurisé

N/A

SecureTextField est un composable basé sur des champs de texte avec état pour écrire un champ de mot de passe.

  • Vous permet d'optimiser la sécurité en coulisses et est fourni avec une UI prédéfinie avec textObfuscationMode.

Cette page explique comment implémenter TextField, styliser l'entrée TextField et configurer d'autres options TextField, comme les options de clavier et la transformation visuelle de la saisie utilisateur.

Choisir l'implémentation TextField

Il existe deux niveaux d'implémentation de TextField :

  1. TextField est l'implémentation Material Design. Il s'agit de celle que nous recommandons, car elle respecte les consignes Material Design :
    • Le style par défaut est rempli.
    • OutlinedTextField correspond à la version de style contour.
  2. BasicTextField permet aux utilisateurs de modifier du texte à l'aide du clavier physique ou virtuel, mais ne fournit aucune décoration comme un indice ou un espace réservé.

TextField(
    state = rememberTextFieldState(initialText = "Hello"),
    label = { Text("Label") }
)

Champ de texte modifiable contenant le mot

OutlinedTextField(
    state = rememberTextFieldState(),
    label = { Text("Label") }
)

Champ de texte modifiable avec une bordure et un libellé violets

Style TextField

TextField et BasicTextField partagent de nombreux paramètres communs pour leur personnalisation. La liste complète des éléments TextField est disponible dans le code source TextField. Voici une liste non exhaustive de quelques paramètres utiles :

  • textStyle
  • lineLimits

TextField(
    state = rememberTextFieldState("Hello\nWorld\nInvisible"),
    lineLimits = TextFieldLineLimits.MultiLine(maxHeightInLines = 2),
    placeholder = { Text("") },
    textStyle = TextStyle(color = Color.Blue, fontWeight = FontWeight.Bold),
    label = { Text("Enter text") },
    modifier = Modifier.padding(20.dp)
)

Champ de texte multiligne, avec deux lignes modifiables et le libellé

Nous vous recommandons d'utiliser TextField plutôt que BasicTextField lorsque votre conception nécessite un élément Material TextField ou OutlinedTextField. Toutefois, vous devez utiliser BasicTextField lorsque vous créez des conceptions qui n'ont pas besoin des décorations de la spécification Material.

Mettre en forme la saisie avec l'API Brush

Vous pouvez utiliser l'API Brush pour appliquer des styles plus avancés à vos TextField. La section suivante décrit comment utiliser un pinceau pour ajouter un dégradé de couleurs à l'entrée TextField.

Pour en savoir plus sur l'utilisation de l'API Brush pour mettre en forme du texte, consultez Activer la mise en forme avancée avec l'API Brush.

Implémenter des dégradés de couleur à l'aide de TextStyle

Pour implémenter un dégradé de couleurs lorsque vous saisissez du texte dans un TextField, définissez le pinceau de votre choix comme TextStyle pour votre TextField. Dans cet exemple, nous utilisons un pinceau intégré avec un linearGradient pour afficher l'effet de dégradé arc-en-ciel lorsque du texte est saisi dans le TextField.

val brush = remember {
    Brush.linearGradient(
        colors = listOf(Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Magenta)
    )
}
TextField(
    state = rememberTextFieldState(), textStyle = TextStyle(brush = brush)
)

Utilisation de buildAnnotatedString et SpanStyle, ainsi que de linearGradient, pour personnaliser uniquement une partie du texte.
Figure 1. Effet de dégradé arc-en-ciel pour le contenu TextField.

Gérer l'état du champ de texte

TextField utilise une classe de détenteur d'état dédiée appelée TextFieldState pour son contenu et sa sélection actuelle. TextFieldState est conçu pour être hissé partout où il s'intègre dans votre architecture. TextFieldState fournit deux propriétés principales :

  • initialText : contenu de TextField.
  • initialSelection : indique où se trouve actuellement le curseur ou la sélection.

Ce qui différencie TextFieldState des autres approches, comme le rappel onValueChange, c'est que TextFieldState encapsule entièrement l'ensemble du flux d'entrée. Cela inclut l'utilisation des structures de données de sauvegarde appropriées, l'intégration des filtres et des formateurs, ainsi que la synchronisation de toutes les modifications provenant de différentes sources.

Vous pouvez utiliser TextFieldState() pour hisser l'état dans TextField. Pour ce faire, nous vous recommandons d'utiliser la fonction rememberTextFieldState(). rememberTextFieldState() crée l'instance TextFieldState dans votre composable, s'assure que l'objet d'état est mémorisé et fournit des fonctionnalités intégrées d'enregistrement et de restauration :

val usernameState = rememberTextFieldState()
TextField(
    state = usernameState,
    lineLimits = TextFieldLineLimits.SingleLine,
    placeholder = { Text("Enter Username") }
)

rememberTextFieldState peut avoir un paramètre vide ou une valeur initiale transmise pour représenter la valeur du texte lors de l'initialisation. Si une valeur différente est transmise lors d'une recomposition ultérieure, la valeur de l'état n'est pas mise à jour. Pour mettre à jour l'état après son initialisation, appelez les méthodes d'édition sur TextFieldState.

TextField(
    state = rememberTextFieldState(initialText = "Username"),
    lineLimits = TextFieldLineLimits.SingleLine,
)

Un TextField avec le texte "Nom d'utilisateur" qui s'affiche à l'intérieur du champ de texte.
Figure 2 : TextField avec "Nom d'utilisateur" comme texte initial.

Modifier le texte avec TextFieldBuffer

Un TextFieldBuffer sert de conteneur de texte modifiable, dont la fonction est semblable à celle d'un StringBuilder. Il contient à la fois le contenu textuel et des informations sur la sélection actuelle.

Vous rencontrez souvent TextFieldBuffer en tant que portée du récepteur sur des fonctions telles que TextFieldState.edit, InputTransformation.transformInput ou OutputTransformation.transformOutput. Dans ces fonctions, vous pouvez lire ou mettre à jour TextFieldBuffer si nécessaire. Ensuite, ces modifications sont soit appliquées à TextFieldState, soit transmises au pipeline de rendu dans le cas de OutputTransformation.

Vous pouvez utiliser des fonctions d'édition standards telles que append, insert, replace ou delete pour modifier le contenu du tampon. Pour modifier l'état de sélection, définissez directement sa variable selection: TextRange ou utilisez des fonctions utilitaires telles que placeCursorAtEnd ou selectAll. La sélection elle-même est représentée par un TextRange, où l'index de début est inclusif et l'index de fin est exclusif. Un TextRange avec des valeurs de début et de fin identiques, comme (3, 3), indique une position du curseur sans aucun caractère actuellement sélectionné.

val phoneNumberState = rememberTextFieldState()

LaunchedEffect(phoneNumberState) {
    phoneNumberState.edit { // TextFieldBuffer scope
        append("123456789")
    }
}

TextField(
    state = phoneNumberState,
    inputTransformation = InputTransformation { // TextFieldBuffer scope
        if (asCharSequence().isDigitsOnly()) {
            revertAllChanges()
        }
    },
    outputTransformation = OutputTransformation {
        if (length > 0) insert(0, "(")
        if (length > 4) insert(4, ")")
        if (length > 8) insert(8, "-")
    }
)

Modifier le texte dans TextFieldState

Il existe plusieurs méthodes qui vous permettent de modifier l'état directement via votre variable d'état :

  • edit : vous permet de modifier le contenu de l'état et vous donne accès aux fonctions TextFieldBuffer pour que vous puissiez utiliser des méthodes telles que insert, replace, append, etc.

    val usernameState = rememberTextFieldState("I love Android")
    // textFieldState.text : I love Android
    // textFieldState.selection: TextRange(14, 14)
    usernameState.edit { insert(14, "!") }
    // textFieldState.text : I love Android!
    // textFieldState.selection: TextRange(15, 15)
    usernameState.edit { replace(7, 14, "Compose") }
    // textFieldState.text : I love Compose!
    // textFieldState.selection: TextRange(15, 15)
    usernameState.edit { append("!!!") }
    // textFieldState.text : I love Compose!!!!
    // textFieldState.selection: TextRange(18, 18)
    usernameState.edit { selectAll() }
    // textFieldState.text : I love Compose!!!!
    // textFieldState.selection: TextRange(0, 18)

  • setTextAndPlaceCursorAtEnd : efface le texte actuel, le remplace par le texte donné et place le curseur à la fin.

    usernameState.setTextAndPlaceCursorAtEnd("I really love Android")
    // textFieldState.text : I really love Android
    // textFieldState.selection : TextRange(21, 21)

  • clearText : efface tout le texte.

    usernameState.clearText()
    // textFieldState.text :
    // textFieldState.selection : TextRange(0, 0)

Pour les autres fonctions TextFieldState, consultez la documentation de référence sur TextFieldState.

Modifier l'entrée utilisateur

Les sections suivantes décrivent comment modifier les saisies utilisateur. La transformation des entrées vous permet de filtrer les entrées TextField pendant que l'utilisateur saisit du texte, tandis que la transformation des sorties met en forme les entrées de l'utilisateur avant qu'elles ne s'affichent à l'écran.

Filtrer les saisies utilisateur avec des transformations d'entrée

Une transformation d'entrée vous permet de filtrer les entrées de l'utilisateur. Par exemple, si votre TextField accepte un numéro de téléphone américain, vous ne devez accepter que 10 chiffres. Les résultats de InputTransformation sont enregistrés dans TextFieldState.

Des filtres intégrés sont disponibles pour les cas d'utilisation courants de InputTransformation. Pour limiter la durée, appelez InputTransformation.maxLength() :

TextField(
    state = rememberTextFieldState(),
    lineLimits = TextFieldLineLimits.SingleLine,
    inputTransformation = InputTransformation.maxLength(10)
)

Transformations d'entrée personnalisées

InputTransformation est une interface à fonction unique. Lorsque vous implémentez votre InputTransformation personnalisé, vous devez remplacer TextFieldBuffer.transformInput :

class CustomInputTransformation : InputTransformation {
    override fun TextFieldBuffer.transformInput() {
    }
}

Pour un numéro de téléphone, ajoutez une transformation d'entrée personnalisée qui n'autorise que la saisie de chiffres dans TextField :

class DigitOnlyInputTransformation : InputTransformation {
    override fun TextFieldBuffer.transformInput() {
        if (!TextUtils.isDigitsOnly(asCharSequence())) {
            revertAllChanges()
        }
    }
}

Chaîner les transformations d'entrée

Pour ajouter plusieurs filtres à votre saisie de texte, enchaînez les InputTransformation à l'aide de la fonction d'extension then. Les filtres sont exécutés de manière séquentielle. Nous vous recommandons d'appliquer d'abord les filtres les plus sélectifs pour éviter les transformations inutiles sur les données qui seront finalement filtrées.

TextField(
    state = rememberTextFieldState(),
    inputTransformation = InputTransformation.maxLength(6)
        .then(CustomInputTransformation()),
)

Après avoir ajouté des transformations d'entrée, l'entrée TextField accepte 10 chiffres maximum.

Mettre en forme les données saisies avant leur affichage

Les OutputTransformation vous permettent de mettre en forme les saisies utilisateur avant qu'elles ne s'affichent à l'écran. Contrairement à InputTransformation, la mise en forme effectuée via OutputTransformation n'est pas enregistrée dans TextFieldState. En reprenant l'exemple de numéro de téléphone précédent, vous devez ajouter des parenthèses et des tirets aux emplacements appropriés :

Un numéro de téléphone américain, correctement formaté avec des parenthèses, des tirets et les indices correspondants.
Figure 3 : Un numéro de téléphone américain au format approprié et avec les indices correspondants.

Il s'agit de la nouvelle façon de gérer les VisualTransformation dans les TextField basés sur les valeurs. La principale différence est que vous n'avez pas à calculer leurs mappages de décalage.

OutputTransformation est une interface de méthode abstraite unique. Pour implémenter un OutputTransformation personnalisé, vous devez remplacer la méthode transformOutput :

class CustomOutputTransformation : OutputTransformation {
    override fun TextFieldBuffer.transformOutput() {
    }
}

Pour mettre en forme un numéro de téléphone, ajoutez une parenthèse ouvrante à l'index 0, une parenthèse fermante à l'index 4 et un tiret à l'index 8 à votre OutputTransformation :

class PhoneNumberOutputTransformation : OutputTransformation {
    override fun TextFieldBuffer.transformOutput() {
        if (length > 0) insert(0, "(")
        if (length > 4) insert(4, ")")
        if (length > 8) insert(8, "-")
    }
}

Ensuite, ajoutez votre OutputTransformation à TextField :

TextField(
    state = rememberTextFieldState(),
    outputTransformation = PhoneNumberOutputTransformation()
)

Fonctionnement combiné des transformations

Le schéma suivant illustre le flux d'entrée de texte, de transformation et de sortie :

Visualisation de la façon dont une entrée de texte est transformée avant de devenir une sortie de texte.
Figure 4. Diagramme montrant comment une entrée de texte est transformée en sortie de texte.
  1. Les entrées sont reçues de la source d'entrée.
  2. L'entrée est filtrée par un InputTransformation, qui est enregistré dans TextFieldState.
  3. L'entrée est transmise via un OutputTransformation pour la mise en forme.
  4. L'entrée est présentée dans TextField.

Définir les options de clavier

TextField vous permet de définir des options de configuration du clavier, telles que la disposition des touches, ou d'activer la correction automatique si le clavier le permet. Certaines options ne sont pas garanties si le clavier logiciel ne respecte pas les options fournies ici. Voici la liste des options de clavier compatibles :

  • capitalization
  • autoCorrect
  • keyboardType
  • imeAction

Ressources supplémentaires