Guide complet Flutter : Le widget Textfield


Avatar de Pierre Courtois

Le widget TextField est l’un des éléments fondamentaux dans une application Flutter, permettant à vos utilisateurs d’entrer du texte et de pouvoir le récupérer. Dans ce tuto, je vous explique comment mettre en place ce widget et en tirer le maximum.


À quoi sert le Widget Textfield dans Flutter ?

Le widget TextField est un composant essentiel dans Flutter permettant à vos utilisateurs de saisir des informations dans une barre de texte. Il peut être utilisé aussi bien pour la saisie de texte dans un formulaire que la création de champs de recherche interactifs. Vous pouvez par exemple l’utiliser pour :

  • Créer un formulaire de connexion : Le champ TextField permet à l’utilisateur de saisir son nom d’utilisateur ou son mot de passe.
  • Ajouter une barre de recherche dans une application : Il peut être utilisé pour filtrer des données en fonction de la saisie de l’utilisateur (comme une barre de recherche dans une application de shopping).
  • Prendre des notes : Dans une application de prise de notes, un TextField permet d’enregistrer des textes rapidement et de manière intuitive.

Comment intégrer un TextField dans Flutter

Une des propriétés les plus importantes lors de la mise en place d’un Textfield est le TextEditingController. En effet, ce widget est utilisé pour contrôler et accéder au texte que l’utilisateur saisit dans le TextField. Il permet de :

  • Récupérer le texte saisi.
  • Mettre à jour le texte dans le champ de manière programmatique.
  • Écouter les modifications du texte si nécessaire.

Il est donc important que chaque TextField que vous allez créer ait son propre TextEditingController. En effet, chaque champ de texte doit pouvoir gérer son propre état indépendamment, et partager un seul contrôleur entre plusieurs TextField peut entraîner des comportements imprévisibles.

Ceci dit, voici un exemple simple de mise en place d’un widget TextField dans une application Flutter :

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Exemple TextField Simple'),
        ),
        body: MyHomePage(),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // Créer un TextEditingController pour le TextField
  TextEditingController _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          // TextField avec un controller
          TextField(
            controller: _controller,  // Associe le controller à ce TextField
            decoration: InputDecoration(
              labelText: 'Entrez votre texte',
            ),
          ),
          SizedBox(height: 20),
          ElevatedButton(
            onPressed: () {
              // Affiche le texte saisi dans la console
              print('Texte saisi: ${_controller.text}');
            },
            child: Text('Afficher le text dans la console'),
          ),
        ],
      ),
    );
  }
} 

Pourquoi un TextField doit toujours être placé dans un StatefulWidget ?

Le widget TextField doit toujours être intégré dans un StatefulWidget, car il est interactif et l’état du texte qu’il contient peut changer au fil du temps, en fonction de ce que l’utilisateur saisit.

Un StatelessWidget ne permet pas de gérer ces modifications, car il est conçu pour afficher des éléments statiques, immuables. À l’inverse, un StatefulWidget est capable de maintenir et d’actualiser son état interne (comme le texte saisi), ce qui est essentiel lorsque vous voulez que le texte saisi soit stocké, modifié ou récupéré via un TextEditingController.

Ainsi, pour que le texte du champ soit correctement mis à jour et que vous puissiez y accéder, il est impératif d’utiliser un StatefulWidget.

Envoyer une entrée dans Firebase

La plupart du temps, vous souhaiterez stocker quelque part le texte entré par l’utilisateur, par exemple dans votre base de données Firebase. Voici un court exemple de comment envoyer un message et son heure d’ajout, vers le back-end :

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart'; // Import de Firestore

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('TextField vers Firebase'),
        ),
        body: MyHomePage(),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // Création du TextEditingController pour le TextField
  TextEditingController _controller = TextEditingController();

  // Fonction pour envoyer les données vers Firestore
  Future<void> _sendDataToFirebase(String text) async {
    // Ajoute le texte dans la collection "messages" de Firestore
    await FirebaseFirestore.instance.collection('messages').add({
      'texte': text,  // Stocker le texte saisi
      'timestamp': FieldValue.serverTimestamp(),  // Ajouter un horodatage
    });
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          // TextField avec un controller pour capturer le texte
          TextField(
            controller: _controller,
            decoration: InputDecoration(
              labelText: 'Entrez un message',
              border: OutlineInputBorder(),
            ),
          ),
          SizedBox(height: 20),
          // Bouton pour envoyer les données vers Firestore
          ElevatedButton(
            onPressed: () {
              _sendDataToFirebase(_controller.text); // Envoyer le texte à Firebase
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('Données envoyées à Firebase')),
              );
              _controller.clear(); // Effacer le champ après envoi
            },
            child: Text('Envoyer à Firebase'),
          ),
        ],
      ),
    );
  }
}

Vider le contenu du Textfield après l’envoi des données

Une fois les données envoyées vers Firebase, vous souhaiterez probablement que le Textfield se vide de son contenu, plutôt que l’utilisateur ait à l’effacer manuellement pour pouvoir écrire un nouveau message.

Pour cela, vous pouvez utiliser la méthode _controller.clear() qui permet de vider le contenu du TextField après qu’une action a été effectuée. Elle effacera simplement le texte actuellement saisi dans le champ de texte en le remplaçant par une chaîne vide ("").

Personnaliser un TextField

Le widget TextField peut être personnalisé de différentes façons pour améliorer l’expérience utilisateur et l’adapter à vos besoins spécifiques. Voici quelques-unes des propriétés les plus courantes et utiles pour personnaliser son comportement ou son design.

decoration

La propriété decoration permet de personnaliser l’apparence du TextField. Elle utilise généralement le widget InputDecoration, qui offre de nombreuses options comme le label, la bordure et les icônes. Par exemple :

TextField(
  decoration: InputDecoration(
    labelText: 'Nom', //Texte qui apparait au dessus du champ quand l'utilisateur se met à taper
    hintText: 'Entrez votre nom', //Text d'indication à l'intérieur du champ
    border: OutlineInputBorder(), // Ajoute une bordure autour du TextField
    prefixIcon: Icon(Icons.person), // Ajoute une icône avant le texte
  ),
)

keyboardType

La propriété keyboardType permet de spécifier le type de clavier qui sera affiché lorsque l’utilisateur tape dans le TextField. Par exemple, si vous attendez une entrée numérique ou une adresse e-mail, vous pouvez ajuster le clavier pour correspondre.

TextField(
  keyboardType: TextInputType.emailAddress, // Affiche un clavier adapté aux emails
  decoration: InputDecoration(
    labelText: 'Email',
  ),
)

Quelques valeurs courantes :

  • TextInputType.text : Le clavier par défaut pour entrer du texte.
  • TextInputType.number : Pour les entrées numériques.
  • TextInputType.emailAddress : Pour saisir une adresse e-mail.

obscureText

Si vous voulez cacher le texte saisi dans le TextField, par exemple pour un mot de passe, vous pouvez utiliser la propriété obscureText.

TextField(
  obscureText: true, // Cache le texte pour les champs de mot de passe
  decoration: InputDecoration(
    labelText: 'Mot de passe',
  ),
)

Lorsque obscureText est défini sur true, le texte est masqué par des points ou des étoiles pour des raisons de confidentialité. Vous pouvez ajouter un bouton qui change son état à false, pour montrer le texte quand l’utilisateur clique dessus.

maxLength

La propriété maxLength vous permet de limiter le nombre de caractères que l’utilisateur peut entrer dans le champ de texte.

TextField(
  maxLength: 20, // Limite à 20 caractères
  decoration: InputDecoration(
    labelText: 'Nom d\'utilisateur',
  ),
)

onChanged

La propriété onChanged permet d’exécuter une fonction chaque fois que le texte dans le TextField change. Cela peut être utile pour des validations en temps réel ou pour mettre à jour l’interface en fonction de ce qui est saisi.

TextField(
  onChanged: (text) {
    print('Le texte a changé : $text'); // Affiche le texte à chaque changement
  },
  decoration: InputDecoration(
    labelText: 'Recherche',
  ),
)

Définir l’action du clavier

La propriété textInputAction permet de spécifier l’action du clavier qui s’affiche lorsque l’utilisateur interagit avec un champ de texte. Elle détermine le type de bouton que l’on verra dans la barre d’outils du clavier (comme « Entrée », « Suivant », « Retour », etc.). Cette action peut être utilisée pour faciliter la navigation entre différents champs de texte ou exécuter des actions spécifiques.

Vous pouvez définir cette propriété en l’associant à une valeur de l’énumération TextInputAction. Les valeurs les plus courantes sont TextInputAction.done, TextInputAction.next, TextInputAction.go, etc. Par exemple :

TextField(
  textInputAction: TextInputAction.next, // Passe au champ suivant quand on appuie sur entrer
  onChanged: (text) {
    print('Le texte est : $text');
  },
)

Les différentes actions possibles sont les suivante :

  • TextInputAction.done : Ce bouton indique que l’utilisateur a terminé la saisie. Le bouton peut afficher « Terminer », « OK » ou « Fermer » en fonction de la plateforme.
  • TextInputAction.go : Utilisé quand une action doit être effectuée, comme soumettre un formulaire ou effectuer une recherche. Sur le bouton, on verra souvent « Go », « Lancer », ou « Exécuter ».
  • TextInputAction.next : C’est l’action pour passer au champ suivant dans un formulaire. Le bouton affichera généralement « Suivant ».
  • TextInputAction.previous : Utilisé pour revenir au champ précédent. Le bouton affiche souvent « Précédent » ou « Retour ».
  • TextInputAction.search : Cette action est souvent utilisée dans des champs de recherche. Le bouton peut afficher « Rechercher », « Chercher », ou parfois l’icône de la loupe.
  • TextInputAction.send : Utilisé pour envoyer un message dans des applications de messagerie. Le bouton sera souvent « Envoyer » ou parfois une icône d’envoi, comme une flèche.

Réaliser une action lors de la soumission du champ

Vous pouvez exécuter une action lorsque l’utilisateur soumet un champ de texte, par exemple en appuyant sur « Done » ou « Entrée » sur le clavier. Avec TextField, utilisez onSubmitted, et avec TextFormField, utilisez onFieldSubmitted. La propriété textInputAction définit la touche du clavier, comme TextInputAction.done pour « Valider » ou TextInputAction.next pour passer au champ suivant.

Voici un exemple tout simple avec le widget TextField :

TextField(
  textInputAction: TextInputAction.done,
  onSubmitted: (value) {
    print('Texte soumis : $value');
  },
  decoration: InputDecoration(hintText: 'Entrez votre texte'),
)

Et voici un autre exemple avec le widget TextFormField :

Form(
  key: GlobalKey<FormState>(),
  child: TextFormField(
    textInputAction: TextInputAction.done,
    onFieldSubmitted: (value) {
      if (Form.of(context).validate()) {
        print('Texte soumis : $value');
      }
    },
    validator: (value) => value!.isEmpty ? 'Champ requis' : null,
    decoration: InputDecoration(hintText: 'Entrez votre texte'),
  ),
)

Conclusion

Le Textfield est un widget très puissant qui va être utilisé dans bon nombre d’applications. Permettre à l’utilisateur d’entrer des informations et de les stocker quelque part pour pouvoir les afficher en temps réel est à la base de presque toutes les applications mobiles.

Maintenant que vous savez utiliser les widgets de base de Flutter, pourquoi ne pas apprendre à transferer des variables et des fonctions, d’un widget vers un autre, pour les utiliser à plusieurs endroits ?

Avatar de Pierre Courtois