Pilotez vos champs de saisie avec TextEditingController et validez toutes les entrées d'un coup grâce à Form et TextFormField.
Ouvrir cette leçon dans KodokonUn champ de saisie sans contrôleur est une boîte noire. TextEditingController vous donne la main : lire controller.text à tout moment, préremplir le champ, le vider après envoi, ou écouter chaque frappe avec addListener. Le contrôleur se crée dans un State, jamais dans build - sinon il serait recréé à chaque reconstruction.
import 'package:flutter/material.dart';
class NicknameField extends StatefulWidget {
const NicknameField({super.key});
@override
State<NicknameField> createState() =>
_NicknameFieldState();
}
class _NicknameFieldState extends State<NicknameField> {
final _controller = TextEditingController();
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return TextField(
controller: _controller,
decoration: const InputDecoration(
labelText: 'Pseudo',
border: OutlineInputBorder(),
),
onSubmitted: (value) => debugPrint(value),
);
}
}Dès qu'un écran compte plusieurs champs à vérifier, adoptez le trio Form, GlobalKey<FormState> et TextFormField. Chaque champ décrit sa règle dans validator : la fonction renvoie un message d'erreur, ou null si tout va bien. Un appel à validate() sur la clé déclenche tous les validateurs d'un coup.
import 'package:flutter/material.dart';
class SignUpForm extends StatefulWidget {
const SignUpForm({super.key});
@override
State<SignUpForm> createState() => _SignUpFormState();
}
class _SignUpFormState extends State<SignUpForm> {
final _formKey = GlobalKey<FormState>();
final _emailController = TextEditingController();
@override
void dispose() {
_emailController.dispose();
super.dispose();
}
void _submit() {
if (_formKey.currentState!.validate()) {
debugPrint('Email : ${_emailController.text}');
}
}
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
decoration: const InputDecoration(
labelText: 'E-mail',
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Champ obligatoire';
}
if (!value.contains('@')) {
return 'Adresse invalide';
}
return null;
},
),
const SizedBox(height: 16),
FilledButton(
onPressed: _submit,
child: const Text('Créer le compte'),
),
],
),
);
}
}Au clic sur le bouton, validate() exécute chaque validator : les messages renvoyés s'affichent en rouge sous les champs concernés, et la méthode renvoie false si au moins un champ est invalide. Votre logique d'envoi reste donc derrière un seul if - impossible de soumettre des données invalides.