Le widget TextField de Flutter est l'élément fondamental pour permettre aux utilisateurs de saisir du texte, des nombres ou d'autres données dans une application. Sa flexibilité provient d'un large éventail de propriétés qui permettent de personnaliser son comportement et son apparence pour s'adapter à divers cas d'utilisation.
Le Contrôleur de Texte : TextEditingController
Le TextEditingController est essentiel pour interagir programmatiquement avec un TextField. Il permet de lire, définir ou effacer le texte du champ, et d'écouter les modifications en temps réel.
import 'package:flutter/material.dart';
class ChampDeSaisieControle extends StatefulWidget {
@override
_ChampDeSaisieControleState createState() => _ChampDeSaisieControleState();
}
class _ChampDeSaisieControleState extends State<ChampDeSaisieControle> {
final TextEditingController _controleurSaisie = TextEditingController();
String _dernierTexte = '';
@override
void initState() {
super.initState();
_controleurSaisie.addListener(_mettreAJourAffichage);
}
void _mettreAJourAffichage() {
setState(() {
_dernierTexte = _controleurSaisie.text;
});
}
@override
void dispose() {
_controleurSaisie.dispose(); // Libérer les ressources
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
controller: _controleurSaisie,
decoration: InputDecoration(
hintText: 'Tapez votre message...',
border: OutlineInputBorder(),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: Text('Texte actuel: "$_dernierTexte"'),
),
ElevatedButton(
onPressed: () {
_controleurSaisie.clear(); // Efface le contenu du champ
},
child: Text('Vider le champ'),
),
],
);
}
}
Gestion du Focus avec FocusNode
Le FocusNode permet de suivre l'état du focus d'un TextField (s'il est sélectionné ou non) et de le manipuler (lui donner ou lui retirer le focus).
import 'package:flutter/material.dart';
class GestionnaireFocus extends StatefulWidget {
@override
_GestionnaireFocusState createState() => _GestionnaireFocusState();
}
class _GestionnaireFocusState extends State<GestionnaireFocus> {
final FocusNode _nœudFocusChamp = FocusNode();
String _statutFocus = 'Non focalisé';
@override
void initState() {
super.initState();
_nœudFocusChamp.addListener(_ecouterFocus);
}
void _ecouterFocus() {
setState(() {
_statutFocus = _nœudFocusChamp.hasFocus ? 'Champ focalisé' : 'Champ non focalisé';
});
print('Focus du champ: $_statutFocus');
}
@override
void dispose() {
_nœudFocusChamp.dispose(); // Important pour éviter les fuites de mémoire
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
focusNode: _nœudFocusChamp,
decoration: InputDecoration(
labelText: 'Entrée avec gestion de focus',
border: OutlineInputBorder(),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: Text('État du focus: $_statutFocus'),
),
ElevatedButton(
onPressed: () {
if (_nœudFocusChamp.hasFocus) {
_nœudFocusChamp.unfocus(); // Retire le focus
} else {
FocusScope.of(context).requestFocus(_nœudFocusChamp); // Donne le focus
}
},
child: Text('Basculer le focus'),
),
],
);
}
}
Personnalisation Visuelle avec InputDecoration
La propriété decoration, qui prend une instance de InputDecoration, est la clé pour styliser un TextField. Elle permet d'ajouter des étiquettes, des indices, des icônes, des messages d'erreur et de définir les bordures.
icon: Icône externe au champ.labelText: Texte d'étiquette qui flotte au-dessus du champ lorsqu'il est focalisé.hintText: Texte d'aide affiché lorsque le champ est vide.helperText: Texte informatif en dessous du champ.prefixIcon/suffixIcon: Icônes placées à l'intérieur du champ, respectivement au début et à la fin.border: Définit le style de la bordure du champ (par exemple,OutlineInputBorderpour une bordure complète).errorText: Message d'erreur affiché sous le champ.
import 'package:flutter/material.dart';
class StyleDeChamp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return TextField(
decoration: InputDecoration(
icon: Icon(Icons.email, color: Colors.blueGrey), // Icône extérieure
labelText: 'Votre Email',
labelStyle: TextStyle(color: Colors.deepPurple),
hintText: 'exemple@domaine.com',
helperText: 'Nous ne partagerons jamais votre email.',
prefixIcon: Icon(Icons.alternate_email), // Icône à l'intérieur avant
suffixIcon: IconButton(
icon: Icon(Icons.clear, color: Colors.redAccent),
onPressed: () { /* Action d'effacement */ },
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.green, width: 2.0),
borderRadius: BorderRadius.circular(12.0),
),
filled: true,
fillColor: Colors.lightBlue.shade50,
),
);
}
}
Configuration du Clavier et des Actions
Les propriétés keyboardType et textInputAction adaptent le clavier virtuel et l'action du bouton d'envoi.
keyboardType: Spécifie le type de clavier à afficher (TextInputType.number,TextInputType.emailAddress,TextInputType.phone, etc.).textInputAction: Définit l'action du bouton en bas à droite du clavier (par exemple,TextInputAction.done,TextInputAction.next,TextInputAction.search,TextInputAction.send).
import 'package:flutter/material.dart';
class ClavierPersonnalise extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
keyboardType: TextInputType.phone, // Clavier optimisé pour les numéros de téléphone
decoration: InputDecoration(
labelText: 'Numéro de contact',
hintText: 'Ex: 06 12 34 56 78',
border: UnderlineInputBorder(),
),
),
SizedBox(height: 20),
TextField(
textInputAction: TextInputAction.send, // Bouton "Envoyer" sur le clavier
onSubmitted: (valeur) {
print('Message à envoyer: $valeur');
// Logique d'envoi...
},
decoration: InputDecoration(
labelText: 'Envoyer un message',
hintText: 'Votre message ici...',
border: OutlineInputBorder(),
),
),
],
);
}
}
Transformation du Texte : obscureText et textCapitalization
obscureText: Lorsque défini àtrue, masque le texte saisi, utile pour les mots de passe.textCapitalization: Contrôle la capitalisation auotmatique du texte (TextCapitalization.wordspour chaque mot,TextCapitalization.sentencespour chaque phrase,TextCapitalization.characterspour toutes les lettres en majuscules,TextCapitalization.nonepar défaut).
import 'package:flutter/material.dart';
class TransformationDeTexte extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
obscureText: true, // Cache le texte (ex: pour un mot de passe)
decoration: InputDecoration(
labelText: 'Mot de passe sécurisé',
border: OutlineInputBorder(),
),
),
SizedBox(height: 20),
TextField(
textCapitalization: TextCapitalization.words, // La première lettre de chaque mot sera en majuscule
decoration: InputDecoration(
labelText: 'Nom complet',
hintText: 'Entrez votre nom et prénom',
border: OutlineInputBorder(),
),
),
],
);
}
}
Écoute des Changements avec onChanged
La propriété onChanged est un callback qui est appelé chaque fois que le texte du champ de saisie est modifié. C'est idéal pour la validation en temps réel ou la mise à jour de l'interface utilisateur.
import 'package:flutter/material.dart';
class EcouteurDeModifications extends StatefulWidget {
@override
_EcouteurDeModificationsState createState() => _EcouteurDeModificationsState();
}
class _EcouteurDeModificationsState extends State<EcouteurDeModifications> {
String _saisieCourante = '';
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
onChanged: (valeur) {
setState(() {
_saisieCourante = valeur;
});
print('Saisie actuelle: $valeur');
},
decoration: InputDecoration(
labelText: 'Tapez quelque chose...',
border: OutlineInputBorder(),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: Text('Texte dynamique: "$_saisieCourante"'),
),
],
);
}
}
Personnalisation du Curseur
Il est possible d'ajuster l'apparence du curseur de saisie à l'aide des propriétés cursorColor, cursorWidth et cursorRadius.
import 'package:flutter/material.dart';
class CurseurEsthetique extends StatelessWidget {
@override
Widget build(BuildContext context) {
return TextField(
cursorColor: Colors.pink,
cursorWidth: 5.0,
cursorRadius: Radius.circular(4.0), // Curseur arrondi
decoration: InputDecoration(
labelText: 'Champ avec un curseur personnalisé',
border: OutlineInputBorder(),
),
);
}
}
Limitation de la Longueur et Gestion du Compteur
Pour restreindre le nombre de caractères qu'un utilisateur peut saisir, utilisez maxLength. Par défaut, cela affiche un compteur de caractères sous le champ. Si vous souhaitez limiter la longueur sans afficher le compteur, vous pouvez le masquer et utiliser un TextInputFormatter.
maxLength: Définit le nombre maximal de caractères. Active le compteur par défaut.inputFormatters: Une liste de formateurs qui peuvent modifier ou valider la saisie.LengthLimitingTextInputFormatterest utilisé pour l'application stricte de la limite.counterText: ''(dansInputDecoration) : Cache le compteur visuel même simaxLengthest défini.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; // Nécessaire pour LengthLimitingTextInputFormatter
class LimitationDeChamp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
maxLength: 15, // Limite à 15 caractères, avec compteur visible
decoration: InputDecoration(
labelText: 'Code postal (15 max, compteur visible)',
border: OutlineInputBorder(),
),
),
SizedBox(height: 20),
TextField(
maxLength: 10, // Définit la limite
inputFormatters: [
LengthLimitingTextInputFormatter(10), // Assure que la limite est appliquée
],
decoration: InputDecoration(
labelText: 'Numéro ID (10 max, sans compteur)',
counterText: '', // Cache le compteur
border: OutlineInputBorder(),
),
),
],
);
}
}