Avez-vous une question? (216) 97 656 803 hajjriadh@gmail.com
Flutter

Créer et valider un formulaire avec Flutter

Un cours complet pour maîtriser Créer et valider un formulaire avec Flutter.

0 chapitres 0 QCM Accès gratuit
 

Créer et valider un formulaire avec Flutter

 
  1. Objectif

    • Dans ce tutoriel flutter, nous allons apprendre à créer et valider un formulaire avec Flutter.
  2. Présentation

    • Les formulaires sont désormais un élément essentiel de toute application mobile ou Web. Les formulaires sont utilisés pour recueillir des informations auprès de l'utilisateur.
    • Selon vos besoins, vos exigences et votre logique, vous pouvez créer un formulaire pour l'utilisateur, y compris l'authentification de l'utilisateur, la recherche, la commande, le filtrage, la réservation, etc.
    • Le formulaire peut comporter des champs de texte, des cases à cocher et des boutons radio.
    • Les formulaires font partie intégrante de toutes les applications mobiles et Web modernes.
    • Il est utilisé pour recueillir des informations auprès des utilisateurs.
    • Dans Flutter le widget Form agit comme un conteneur pour regrouper et valider plusieurs champs de formulaire.
    • Lors de la création du formulaire, fournissez un fichier GlobalKey. Cela identifie de manière unique le Formet permet la validation du formulaire dans une étape ultérieure.
    • Le widget form utilise le widget enfant TextFormField pour permettre aux utilisateurs de saisir le champ de texte. Ce widget affiche un champ de texte de conception de matériau et nous permet également d'afficher les erreurs de validation lorsqu'elles se produisent.
  3. Créer un formulaire

    • Un widget de form est fourni par flutter pour créer des formulaires.
    • Il agit comme un conteneur, ce qui nous permet de regrouper plusieurs champs de formulaire.
    • Le widget de form agit comme un conteneur, ce qui nous permet de regrouper et de valider les multiples champs du formulaire.
    • Lorsque vous créez un formulaire, il est nécessaire de fournir le GlobalKey. Cette clé identifie le formulaire de manière unique et vous permet d'effectuer toute validation dans les champs du formulaire.
    • Pour créer un formulaire avec Flutter, vous pouvez utiliser les widgets TextField pour les entrées de texte, DropdownButton pour les menus déroulants, Radio pour les boutons radio, Checkbox pour les cases à cocher, et ElevatedButton pour les boutons d'action.
  4. Code source de la vidéo
      form_advanced_page.dart
        import 'package:flutter/material.dart';
        
        class FormAdvancedPage extends StatefulWidget {
          const FormAdvancedPage({super.key});
        
          @override
          State<FormAdvancedPage> createState() => _FormAdvancedPageState();
        }
        
        class _FormAdvancedPageState extends State<FormAdvancedPage> {
          final _formKey = GlobalKey<FormState>();
        
          String? _selectedCountry;
          String? _gender;
          bool _newsletter = false;
          double _age = 18;
        
          final List<String> _countries = [
            "Tunisie",
            "Algérie",
            "Maroc",
            "France",
          ];
        
          void _submit() {
            if (!_formKey.currentState!.validate()) return;
        
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text(
                    "VALIDÉ ✓ — Pays: $_selectedCountry — Genre: $_gender — Âge: ${_age.toInt()} — Newsletter: $_newsletter"),
              ),
            );
          }
        
          @override
          Widget build(BuildContext context) {
            return Scaffold(
              appBar: AppBar(
                title: const Text("Formulaire — Niveau Avancé"),
              ),
              body: SingleChildScrollView(
                padding: const EdgeInsets.all(16),
                child: Form(
                  key: _formKey,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
        
                      // --- Dropdown ---
                      DropdownButtonFormField<String>(
                        decoration: const InputDecoration(
                          labelText: "Choisir un pays",
                          border: OutlineInputBorder(),
                        ),
                        items: _countries
                            .map((c) => DropdownMenuItem(
                                  value: c,
                                  child: Text(c),
                                ))
                            .toList(),
                        onChanged: (v) => setState(() => _selectedCountry = v),
                        validator: (v) =>
                            v == null ? "Veuillez choisir un pays" : null,
                      ),
                      const SizedBox(height: 20),
        
                      // --- Radio ---
                      const Text("Genre :", style: TextStyle(fontSize: 16)),
                      RadioListTile(
                        title: const Text("Homme"),
                        value: "Homme",
                        groupValue: _gender,
                        onChanged: (v) => setState(() => _gender = v),
                      ),
                      RadioListTile(
                        title: const Text("Femme"),
                        value: "Femme",
                        groupValue: _gender,
                        onChanged: (v) => setState(() => _gender = v),
                      ),
                      if (_gender == null)
                        const Padding(
                          padding: EdgeInsets.only(left: 16),
                          child: Text(
                            "Veuillez choisir un genre",
                            style: TextStyle(color: Colors.red),
                          ),
                        ),
        
                      const SizedBox(height: 20),
        
                      // --- Slider ---
                      Text("Âge : ${_age.toInt()} ans"),
                      Slider(
                        value: _age,
                        min: 10,
                        max: 80,
                        divisions: 70,
                        label: _age.toInt().toString(),
                        onChanged: (v) => setState(() => _age = v),
                      ),
                      const SizedBox(height: 20),
        
                      // --- Switch ---
                      SwitchListTile(
                        value: _newsletter,
                        title: const Text("Recevoir la newsletter"),
                        onChanged: (v) => setState(() => _newsletter = v),
                      ),
                      const SizedBox(height: 30),
        
                      // --- Bouton Soumettre ---
                      SizedBox(
                        width: double.infinity,
                        child: ElevatedButton(
                          onPressed: () {
                            if (_gender == null) setState(() {});
                            _submit();
                          },
                          child: const Text("Soumettre"),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            );
          }
        }
        
      form_page.dart
        import 'package:flutter/material.dart';
        import 'form_advanced_page.dart';
        
        class FormPage extends StatefulWidget {
          const FormPage({super.key});
        
          @override
          State<FormPage> createState() => _FormPageState();
        }
        
        class _FormPageState extends State<FormPage> {
          // Clé globale pour identifier et contrôler le formulaire
          final _formKey = GlobalKey<FormState>();
        
          // Controllers pour récupérer les valeurs saisies
          final _nameCtrl = TextEditingController();
          final _emailCtrl = TextEditingController();
          final _passCtrl = TextEditingController();
        
          // Valeur de la checkbox
          bool _accepted = false;
        
          // Libération des contrôleurs pour éviter les fuites mémoire
          @override
          void dispose() {
            _nameCtrl.dispose();
            _emailCtrl.dispose();
            _passCtrl.dispose();
            super.dispose();
          }
        
          // --- Fonction de validation spécifique à l'email ---
          // Cette fonction prend en entrée une valeur de type String? (peut être null)
          // et retourne soit un message d'erreur (String), soit null si le champ est valide.
          String? _emailValidator(String? value) {
            // 1️ Vérification si le champ est vide ou null
            //Vide : signifie que la chaîne existe (String non nulle), mais ne contient aucun caractère ou uniquement des espaces. Exemple : "" ou " ".
            //Null : signifie que la variable n’a pas de valeur du tout, elle n’existe pas encore ou n’a pas été initialisée.
            if (value == null || value.trim().isEmpty) {
              // trim() supprime les espaces avant et après la chaîne
              // Si le champ est vide, on retourne un message d'erreur
              return 'Veuillez entrer un email';
            }
        
            // 2️ Définition d'une expression régulière (Regex) simple pour vérifier le format d'un email
            final emailRegex = RegExp(r'^[\w\.-]+@[\w\.-]+\.\w+$');
            /*
            Explication du Regex :
            ^          → début de la chaîne
            [\w\.-]+   → un ou plusieurs caractères alphanumériques, '.' ou '-'
            @          → caractère '@' obligatoire
            [\w\.-]+   → un ou plusieurs caractères alphanumériques, '.' ou '-'
            \.         → un point obligatoire
            \w+        → un ou plusieurs caractères alphanumériques pour le domaine
            $          → fin de la chaîne
          */
        
            // 3️ Vérification si l'email correspond au format attendu
            if (!emailRegex.hasMatch(value.trim())) {
              // Si la regex ne correspond pas, retourne un message d'erreur
              return 'Email invalide';
            }
        
            // 4️ Si toutes les vérifications sont passées, retourne null (champ valide)
            return null;
          }
        
          // --- Fonction appelée lors de l'appui sur le bouton "Soumettre" ---
          void _submit() {
            // 1️- Validation de tous les champs du formulaire
            // _formKey.currentState?.validate() renvoie true si tous les champs sont valides
            // Le "?? false" permet de gérer le cas où currentState est null
            final isValid = _formKey.currentState?.validate() ?? false;
        
            // 2️- Si un champ est invalide, on arrête la fonction ici
            if (!isValid) return;
        
            // 3️- Récupération des valeurs saisies
            // trim() supprime les espaces inutiles au début et à la fin
            final name = _nameCtrl.text.trim();
            final email = _emailCtrl.text.trim();
        
            // 4️- Affichage d'une notification à l'utilisateur
            // ScaffoldMessenger permet d'afficher un SnackBar
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('Succès ! Bienvenue $name — email : $email')),
            );
        
            // Optionnel : tu peux réinitialiser le formulaire après validation
            // _formKey.currentState?.reset();
            // setState(() => _accepted = false);
          }
        
          @override
          Widget build(BuildContext context) {
            return Scaffold(
              appBar: AppBar(
                elevation: 4,
                title: const Text('Formulaire avec validation'),
                backgroundColor: Colors.blueAccent,
                foregroundColor: Colors.white,
                actions: [IconButton(onPressed: () {}, icon: Icon(Icons.help))],
              ),
        
              body: SingleChildScrollView(
                padding: const EdgeInsets.all(16),
        
                child: Form(
                  key: _formKey,
        
                  child: Column(
                    children: [
                      // --- Champ Nom ---
                      TextFormField(
                        controller: _nameCtrl,
                        decoration: const InputDecoration(
                          labelText: 'Nom',
                          hintText: 'Ex : Riadh Hajji',
                          border: OutlineInputBorder(),
                        ),
                        validator: (value) {
                          if (value == null || value.trim().isEmpty) {
                            return 'Veuillez entrer votre nom';
                          }
                          if (value.trim().length < 2) {
                            return 'Le nom doit contenir au moins 2 caractères';
                          }
                          return null;
                        },
                      ),
        
                      const SizedBox(height: 16),
        
                      // --- Champ Email ---
                      TextFormField(
                        controller: _emailCtrl,
                        decoration: const InputDecoration(
                          labelText: 'Email',
                          hintText: 'exemple@domaine.com',
                          border: OutlineInputBorder(),
                        ),
                        keyboardType: TextInputType.emailAddress,
                        validator: _emailValidator,
                      ),
        
                      const SizedBox(height: 16),
        
                      // --- Champ Mot de passe ---
                      TextFormField(
                        controller: _passCtrl,
                        decoration: InputDecoration(
                          labelText: 'Mot de passe',
                          hintText: 'Au moins 6 caractères',
                          border: const OutlineInputBorder(),
                          suffixIcon: IconButton(
                            onPressed: () {},
                            icon: const Icon(Icons.visibility),
                          ),
                          suffixIconColor: Colors.blue,
                        ),
                        obscureText: true,
                        validator: (value) {
                          if (value == null || value.isEmpty) {
                            return 'Veuillez entrer un mot de passe';
                          }
                          if (value.length < 6) {
                            return 'Mot de passe trop court (>=6)';
                          }
                          return null;
                        },
                      ),
        
                      const SizedBox(height: 16),
        
                      // --- Checkbox avec validation ---
                      // On utilise FormField<bool> pour intégrer la checkbox dans le Form
                      FormField<bool>(
                        initialValue:
                            _accepted, // valeur initiale (bool) de la checkbox
                        validator: (value) {
                          // Fonction de validation appelée lors de _formKey.currentState?.validate()
                          // Si la checkbox n'est pas cochée, on retourne un message d'erreur
                          if (value != true) {
                            return 'Vous devez accepter les conditions';
                          }
                          return null; // sinon pas d'erreur
                        },
                        builder: (state) {
                          // builder permet de créer l'UI personnalisée de la checkbox
                          return Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Row(
                                children: [
                                  Checkbox(
                                    value:
                                        state.value, // valeur actuelle de la checkbox
                                    onChanged: (v) {
                                      state.didChange(
                                        v,
                                      ); // notifie le FormField du changement
                                      setState(
                                        () => _accepted = v ?? false,
                                      ); // met à jour l'état local
                                    },
                                  ),
                                  const SizedBox(width: 8),
                                  const Expanded(
                                    child: Text(
                                      "J'accepte les conditions d'utilisation",
                                      style: TextStyle(
                                        color: Colors.blue,
                                        fontWeight: FontWeight.bold,
                                      ),
                                    ),
                                  ),
                                ],
                              ),
        
                              // --- Affichage du message d’erreur si validation échoue ---
                              if (state.hasError)
                                Padding(
                                  padding: const EdgeInsets.only(left: 12),
                                  child: Text(
                                    state.errorText ??
                                        '', // texte de l'erreur renvoyé par validator
                                    style: TextStyle(
                                      color: Theme.of(
                                        context,
                                      ).colorScheme.error, // couleur rouge par défaut
                                    ),
                                  ),
                                ),
                            ],
                          );
                        },
                      ),
        
                      const SizedBox(height: 24),
        
                      // --- Bouton Soumettre ---
                      SizedBox(
                        width: double.infinity,
                        child: ElevatedButton(
                          onPressed: _submit,
                          child: const Padding(
                            padding: EdgeInsets.symmetric(vertical: 14.0),
                            child: Text('Soumettre', style: TextStyle(fontSize: 16)),
                          ),
                        ),
                      ),
        
                      const SizedBox(height: 20),
        
                      // --- Bouton pour aller à la 2e page ---
                      SizedBox(
                        width: double.infinity,
                        child: OutlinedButton(
                          onPressed: () {
                            Navigator.push(
                              context,
                              MaterialPageRoute(
                                builder: (_) => const FormAdvancedPage(),
                              ),
                            );
                          },
                          child: const Text(
                            "Accéder aux exercices avancés",
                            style: TextStyle(fontSize: 15),
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            );
          }
        }
        
      main.dart
        import 'package:flutter/material.dart';
        import 'form_page.dart';
        
        void main() {
          runApp(const MyApp());
        }
        
        class MyApp extends StatelessWidget {
          const MyApp({super.key});
        
          @override
          Widget build(BuildContext context) {
            return MaterialApp(
              debugShowCheckedModeBanner: false,
              title: 'Form Validation Demo',
              theme: ThemeData(
                primarySwatch: Colors.blue,
        
                inputDecorationTheme: InputDecorationTheme(
                  labelStyle: const TextStyle(
                    color: Colors.blue,
                    fontWeight: FontWeight.bold,
                  ),
                  hintStyle: const TextStyle(
                    color: Colors.grey,
                    fontStyle: FontStyle.italic,
                  ),
                  // ===== Bordure avec radius =====
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(8),
                    borderSide: const BorderSide(
                      color: Colors.blue,
                      width: 2,
                    ),
                  ),
                  enabledBorder: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(8),
                    borderSide: const BorderSide(
                      color: Colors.blueAccent,
                      width: 1.5,
                    ),
                  ),
                  focusedBorder: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(8),
                    borderSide: const BorderSide(
                      color: Colors.blue,
                      width: 2,
                    ),
                  ),
                  errorBorder: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(8),
                    borderSide: const BorderSide(
                      color: Colors.red,
                      width: 1.5,
                    ),
                  ),
                  focusedErrorBorder: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(8),
                    borderSide: const BorderSide(
                      color: Colors.red,
                      width: 2,
                    ),
                  ),
                ),
              ),
              home: const FormPage(),
            );
          }
        }
    • Créer un formulaire avec une clé globale (GlobalKey)
      1. Pour créer un formulaire et pour commencer nous devons fournir une clé globale (GlobalKey).
      2. Définition d'une GlobalKey

        • Avant tout la clé globale (GlobalKey) est utilisée pour identifier de manière unique le formulaire et permet la validation du formulaire lors d'une étape ultérieure.
        • GlobalKey, il s'agit d'une clé unique sur l'ensemble de l'application. Grâce à cette clé, on peut trouver et accéder au Élément en question et récupérer ses State et Widget.
        • final _formKey = GlobalKey();
        • Pour créer un formulaire, vous devez d'abord définir une clé globale (GlobalKey). Dans notre exemple, nous avons défini a _formKey comme une clé globale.
        • Une clé globale ou GlobalKey est une clé qui, lorsqu'elle est transmise en tant que clé dans un widget, peut différencier le widget de tous les widgets d'une arborescence de widgets.
      3. Exemple

          Créer un formulaire avec Flutter

      4. Explication du code

        • Tout d'abord une classe personnalisée de nom MonFormulaire est créée.
        • Ensuite une clé globale est définie à l'intérieur de cette classe avec le nom _formKey, qui contient FormState, utilisé pour recevoir les widgets de formulaire (Form).
        • Certains styles personnalisés se trouvent également dans la méthode Build de cette classe et utilisent le périphérique TextFormField pour fournir des champs de formulaire tels que le nom, le numéro de téléphone, la date de naissance ou simplement un champ standard.
        • InputDecoration est utilisé dans TextFormField pour styliser votre formulaire en modifiant les propriétés telles que les bordures, les étiquettes, les icônes, les conseils, les styles, etc.
        • Enfin, nous avons ajouté un bouton pour soumettre le formulaire.
    • Création d'un formulaire avec validation
      1. Validation avec déclencheurs

      2. Les trois étapes suivantes doivent être suivies pour créer un formulaire de validation dans Flutter.
        • Étape 1: Tout d'abord, utilisez le widget de formulaire avec la clé globale.
        • Étape 2: Puis, utilisez TextFormField pour fournir au champ de saisie une propriété de validation.
        • Étape 3: Enfin créez un bouton qui, lorsqu'il est cliqué, valide les champs du formulaire flutter, et s'il y a une erreur, il l'affiche.
      3. Exemple

          Créer un formulaire avec Flutter

      4. Explication du code

        • Pour valider les propriétés d'entrée, nous avons utilisé validator() dans TextFormField. Chaque fois que l'utilisateur saisit la mauvaise entrée, la fonction validator() renvoie une chaîne contenant un message d'erreur ; sinon, il renvoie une valeur nulle .
        • Cela doit être assuré que le TextFormField n'a pas besoin d'être vide ; sinon, il renverra un message d'erreur.
  5. 2- Validation avec autovalidate
    • Dans Flutter, la validation automatique fait généralement référence à la validation automatique des entrées utilisateur dans les champs de formulaire lorsque l’utilisateur interagit avec eux, sans nécessiter de déclencheurs de validation explicites tels que la soumission d’un formulaire ou l’appui sur un bouton « valider ».
    • Flutter fournit un cadre flexible pour la création de formulaires et la validation. Pour obtenir une validation automatique dans Flutter, vous pouvez suivre ces étapes :
      • **Étape 1 : Création du projet**
        • 1. Créez un nouveau projet Flutter dans votre environnement de développement (par exemple, avec Flutter CLI ou dans un IDE comme VSCode ou Android Studio).
      • **Étape 2 : Structure de base de l'application**
        • 2. Dans le fichier `main.dart`, créez une application Flutter de base avec une barre de navigation, un titre et un corps.
      • **Étape 3 : Ajout de TextFormFields**
        • 3. Dans le corps de l'application, ajoutez deux `TextFormField`.
        • 4. Pour chaque `TextFormField`, ajoutez le texte d'invite (`hintText`) pour indiquer ce que l'utilisateur doit saisir.
      • **Étape 4 : Activation de la validation automatique**
        • 5. Pour activer la validation automatique, définissez `autovalidateMode` sur `AutovalidateMode.always` dans le widget `Form` qui englobe les `TextFormField`.
        • ```dart
          autovalidateMode: AutovalidateMode.always,
          ```
      • **Étape 5 : Validation de l'e-mail**
        • 6. Pour le premier `TextFormField`, ajoutez une validation de l'e-mail en utilisant `validator`.
        • 7. Utilisez une expression régulière pour valider l'e-mail.
        • 8. Si l'e-mail n'est pas valide, retournez un message d'erreur.
      • **Étape 6 : Validation du mot de passe**
        • 9. Pour le deuxième `TextFormField`, ajoutez une validation de mot de passe.
        • 10.Vérifiez la longueur du mot de passe, la présence de minuscules, de majuscules, de chiffres et de caractères spéciaux.
          • 10.1.Vérifiez que la longueur du mot de passe est comprise entre 8 et 12 caractères.
              validator: (value) {
                if (value == null || value.isEmpty) {
                  return 'Veuillez entrer un mot de passe.';
                }
                
                if (value.length < 8 || value.length > 12) {
                  return 'Le mot de passe doit contenir entre 8 et 12 caractères.';
                }
                // Continuez avec les autres vérifications...
              },
          • 10.2.Assurez-vous que le mot de passe contient au moins une lettre minuscule (a-z).
              if (!value.contains(RegExp(r'[a-z]'))) {
                return 'Le mot de passe doit contenir au moins une lettre minuscule.';
              }
          • 10.3.Assurez-vous que le mot de passe contient au moins une lettre majuscule (A-Z).
              if (!value.contains(RegExp(r'[A-Z]'))) {
                return 'Le mot de passe doit contenir au moins une lettre majuscule.';
              }
          • 10.4.Assurez-vous que le mot de passe contient au moins un chiffre (0-9).
              if (!value.contains(RegExp(r'[0-9]'))) {
                return 'Le mot de passe doit contenir au moins un chiffre.';
              }
          • 10.5.Assurez-vous que le mot de passe contient au moins un caractère spécial (par exemple, !@#$%^&*()).
              if (!value.contains(RegExp(r'[!@#$%^&*()]'))) {
                return 'Le mot de passe doit contenir au moins un caractère spécial.';
              }
        • 11. Si le mot de passe ne respecte pas les critères de validation, retournez un message d'erreur.
      • **Étape 7 : Ajout de l'icône pour afficher/masquer le mot de passe**
        • 12. À l'intérieur du TextFormField pour le mot de passe, ajoutez un suffixIcon avec un GestureDetector et une icône (par exemple, une icône "œil").
        • 13.Utilisez un état (par exemple, _obscurePassword) pour suivre si le mot de passe doit être masqué ou non.
        • 14.Lorsque l'utilisateur clique sur l'icône, utilisez setState pour inverser l'état _obscurePassword.
        • 15.Utilisez _obscurePassword comme valeur pour la propriété obscureText du TextFormField pour masquer ou afficher le mot de passe en fonction de l'état.
      • **Étape 8 : Soumission du formulaire**
        • 16. Ajoutez un bouton "Submit" en bas du formulaire.
        • 17. Lorsque le bouton "Submit" est cliqué, vérifiez si le formulaire est valide en utilisant `_formKey.currentState.validate()`.
        • 18. Si le formulaire est valide, affichez un message de confirmation. Sinon, les messages d'erreur seront automatiquement affichés sous les champs de texte invalides.
        • En suivant ces étapes, vos apprenants pourront créer une application Flutter avec la validation automatique des champs de texte pour l'e-mail et le mot de passe. Assurez-vous de leur fournir le code d'exemple pour chaque étape et de les encourager à expérimenter et à comprendre comment chaque partie fonctionne
        Solution
          import 'package:flutter/material.dart';
          
          void main() => runApp(const MyApp());
          
          class MyApp extends StatelessWidget {
            const MyApp({super.key});
          
            @override
            Widget build(BuildContext context) {
              return const MaterialApp(debugShowCheckedModeBanner: false,
                home: MyForm(),
              );
            }
          }
          
          class MyForm extends StatefulWidget {
            const MyForm({super.key});
            @override
            _MyFormState createState() => _MyFormState();
          }
          
          class _MyFormState extends State<MyForm> {
            final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
            bool _obscurePassword = true; // Par défaut, le mot de passe est masqué
          
            @override
            Widget build(BuildContext context) {
              return Scaffold(
                appBar: AppBar(
                  title: const Text('Formulaire d\'autovalidation'),
                ),
                body: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Form(
                    key: _formKey,
                    autovalidateMode: AutovalidateMode.always,
                    child: Column(
                      children: [
                        Padding(
                          padding: const EdgeInsets.symmetric(vertical: 8.0),
                          child: TextFormField(
                            decoration: const InputDecoration(
                              labelText: 'Email',
                              hintText: 'Entrez votre adresse email',
                            ),
                            validator: (value) {
                                  if (value == null || value.isEmpty) {
                                    return 'Veuillez entrer une adresse email.';
                                  }
                                  
                                  // Expression régulière pour la validation de l'adresse e-mail
                                  const pattern = r'^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$';
                                  final regex = RegExp(pattern);
                                  
                                  if (!regex.hasMatch(value)) {
                                    return 'Veuillez entrer une adresse email valide.';
                                  }
                                  return null;
                                },
                          ),
                        ),
                        Padding(
                          padding: const EdgeInsets.symmetric(vertical: 12.0),
                          child: TextFormField(
                            decoration:  InputDecoration(
                              labelText: 'Password',
                              hintText: 'Entrez votre mot de passe',
                              suffixIcon: GestureDetector(
                                onTap: () {
                                  setState(() {
                                    _obscurePassword = !_obscurePassword;
                                  });
                                },
                                child: Icon(
                                  _obscurePassword
                                      ? Icons.visibility_off
                                      : Icons.visibility,
                                ),
                              ),
                            ),
                            validator: (value) {
                                        if (value == null || value.isEmpty) {
                                          return 'Veuillez entrer un mot de passe.';
                                        }
          
                                        // Vérifier la longueur du mot de passe
                                        if (value.length < 8 || value.length > 12) {
                                          return 'Le mot de passe doit contenir entre 8 et 12 caractères.';
                                        }
          
                                        // Vérifier la présence d'au moins une minuscule
                                        if (!value.contains(RegExp(r'[a-z]'))) {
                                          return 'Le mot de passe doit contenir au moins une lettre minuscule.';
                                        }
          
                                        // Vérifier la présence d'au moins une majuscule
                                        if (!value.contains(RegExp(r'[A-Z]'))) {
                                          return 'Le mot de passe doit contenir au moins une lettre majuscule.';
                                        }
          
                                        // Vérifier la présence d'au moins un chiffre
                                        if (!value.contains(RegExp(r'[0-9]'))) {
                                          return 'Le mot de passe doit contenir au moins un chiffre.';
                                        }
          
                                        // Vérifier la présence d'au moins un caractère spécial
                                        if (!value.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]'))) {
                                          return 'Le mot de passe doit contenir au moins un caractère spécial.';
                                        }
          
                                        return null;
                                     },
                            obscureText: _obscurePassword,
                          ),
                        ),
                        ElevatedButton(
                          child: const Text('Submit'),
                          onPressed: () {
                            if (_formKey.currentState?.validate() == true) {
                              // Form is valid, process the data
                              // You can access form data using _formKey.currentState!.fields
                            }
                          },
                        ),
                      ],
                    ),
                  ),
                ),
              );
            }
          }
  • Applications

    • App-01
      • Travail demandé

        • Pour commencer, créer une page de connexion simple contenant les champs suivants :
          • E-mail
          • Nom & Prénom
          • Numéro de téléphone
          • Mot de passe
        • Pour la validation, nous souhaitons que les utilisateurs de notre application remplissent les informations correctes dans chacun de ces champs. La logique sera définie comme telle :
          • Tout d'abord, pour le champ du nom, nous souhaitons que l'utilisateur saisisse un prénom et un nom de famille valides, qui peuvent être accompagnés d'initiales.
          • Pour le champ email, nous voulons un email valide qui contient quelques caractères avant le signe "@", ainsi que le domaine email à la fin de l'email.
          • Ensuite pour la validation du numéro de téléphone, l'utilisateur doit saisir 11 chiffres en commençant par le chiffre zéro.
          • Enfin, pour la validation de notre mot de passe, nous attendons de l'utilisateur qu'il utilise une combinaison d'une lettre majuscule, d'une lettre minuscule, d'un chiffre et d'un caractère spécial.
          • Ce n'est que lorsque la saisie de l'utilisateur correspond à ce qui précède que nous voulons accepter sa saisie avant de faire des demandes, telles que l'envoi à un serveur ou l'enregistrement dans une base de données.
        Solution
        import 'package:flutter/material.dart';
        
        void main() => runApp(const MyApp());
        
        class MyApp extends StatefulWidget {
          const MyApp({Key? key}) : super(key: key);
        
          @override
          _MyAppState createState() => _MyAppState();
        }
        
        class _MyAppState extends State<MyApp> {
          final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
          AutovalidateMode _autoValidate = AutovalidateMode.disabled;
          String? _name;
          String? _mobile;
          String? _email;
          void _validateInputs() {
            if (_formKey.currentState!.validate()) {
              _formKey.currentState!.save();
            } else {
              setState(() {
                _autoValidate = AutovalidateMode.always;
              });
            }
          }
        
          @override
          Widget build(BuildContext context) {
            return MaterialApp(
              home: Scaffold(
                appBar: AppBar(
                  title: const Text('Form Validation'),
                ),
                body: SingleChildScrollView(
                  child: Container(
                    margin: const EdgeInsets.all(15.0),
                    child: Form(
                      key: _formKey,
                      autovalidateMode: _autoValidate,
                      child: formUI(),
                    ),
                  ),
                ),
              ),
            );
          }
        
          Widget formUI() {
            return Column(
              children: <Widget>[
                TextFormField(
                  decoration: const InputDecoration(labelText: 'Name'),
                  keyboardType: TextInputType.text,
                  validator: validateName,
                  onSaved: (String? val) {
                    _name = val;
                  },
                ),
                TextFormField(
                  decoration: const InputDecoration(labelText: 'Mobile'),
                  keyboardType: TextInputType.phone,
                  validator: validateMobile,
                  onSaved: (String? val) {
                    _mobile = val;
                  },
                ),
                TextFormField(
                  decoration: const InputDecoration(labelText: 'Email'),
                  keyboardType: TextInputType.emailAddress,
                  validator: validateEmail,
                  onSaved: (String? val) {
                    _email = val;
                  },
                ),
                const SizedBox(
                  height: 10.0,
                ),
                OutlinedButton(
                  onPressed: _validateInputs,
                  child: const Text('Validate'),
                )
              ],
            );
          }
        
          String? validateName(String? value) {
            if (value!.isEmpty) {
              return 'Name cannot be empty';
            }
            if (value.length < 3) {
              return 'Name must be more than 2 charater';
            } else {
              return null;
            }
          }
        
          String? validateMobile(String? value) {
            if (value!.isEmpty) {
              return 'Phone number cannot be empty';
            }
            if (value.length != 10) {
              return 'Mobile Number must be of 10 digit';
            } else {
              return null;
            }
          }
        
          String? validateEmail(String? value) {
            String pattern =
                r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
            RegExp regex = RegExp(pattern);
            if (value!.isEmpty) {
              return 'Email cannot be empty';
            }
            if (!regex.hasMatch(value)) {
              return 'Enter Valid Email';
            } else {
              return null;
            }
          }
        }
        
    • App-02
      • Travail demandé

        • Créez une application Flutter comme l'illustre le schéma suivant:
        • Créer et valider un formulaire avec Flutter

        Solution
        import 'package:flutter/material.dart';
        
        void main() => runApp(MyWidget());
        
        class MyWidget extends StatelessWidget {
          const MyWidget({super.key});
        
          @override
          Widget build(BuildContext context) {
            return MaterialApp(
              title: 'Application Flutter',
              debugShowCheckedModeBanner: false,
              home: Scaffold(
                appBar: AppBar(title: const Text("Connexion")),
                body: const LoginForm(),
              ),
            );
          }
        }
        
        class LoginForm extends StatefulWidget {
          const LoginForm({super.key});
        
          @override
          _LoginFormState createState() => _LoginFormState();
        }
        
        class _LoginFormState extends State&<LoginForm> {
          final _formKey = GlobalKey<FormState>();
          String? _email, _password;
        
          @override
          Widget build(BuildContext context) {
            return Form(
              key: _formKey,
              child: Column(
                children: [
                  Padding(
                    padding: const EdgeInsets.fromLTRB(40, 10, 40, 0),
                    child: TextFormField(
                      validator: (input) {
                        if (input!.isEmpty) {
                          return 'Entrer une adresse email valide';
                        }
                        return null;
                      },
                      onSaved: (input) => _email = input!,
                      decoration: const InputDecoration(labelText: 'Email'),
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.fromLTRB(40, 6, 40, 0),
                    child: TextFormField(
                      validator: (input) {
                        if (input!.length < 6) {
                          return 'Le mot de passe doit contenir au moins 6 caractères';
                        }
                      },
                      onSaved: (input) => _password = input!,
                      decoration: const InputDecoration(labelText: 'Mot de passe'),
                      obscureText: true,
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.fromLTRB(40, 6, 40, 10),
                    child: ElevatedButton(
                      onPressed: () {
                        if (_formKey.currentState!.validate()) {
                          _formKey.currentState!.save();
                          // Appel API de connexion avec _email et _password
                        }
                      },
                      child: const Text('Se connecter'),
                    ),
                  ),
                ],
              ),
            );
          }
        }
        
    • App-03
      • Travail demandé

        • Vous allez implémenter une application Flutter simple qui affiche un écran de connexion. L'écran contient deux champs de texte : Email et mot de passe.
        • Votre application doive être appliquée selon la conception spécifiée comme indiqué ci-dessous
        Solution
        import 'package:flutter/material.dart';
        
        void main() => runApp(MyWidget());
        
        class MyWidget extends StatelessWidget {
          const MyWidget({super.key});
        
          @override
          Widget build(BuildContext context) {
            return MaterialApp(
              title: 'Valider Formulaire',
              debugShowCheckedModeBanner: false,
              home: Scaffold(
                appBar: AppBar(title: const Text("Connexion")),
                body: const ValiderFormulaire(),
              ),
            );
          }
        }
        
        class ValiderFormulaire extends StatefulWidget {
          const ValiderFormulaire({super.key});
        
          @override
          _ValiderFormulaireState createState() => _ValiderFormulaireState();
        }
        
        class _ValiderFormulaireState extends State<ValiderFormulaire> {
          final _formKey = GlobalKey<FormState>();
          bool _accepterCGU = false;
        
          @override
          Widget build(BuildContext context) {
            return Form(
              key: _formKey,
              child: Container(
                child: Padding(
                  padding: const EdgeInsets.fromLTRB(40, 4, 40, 4),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      TextFormField(
                        decoration: const InputDecoration(labelText: 'Nom'),
                        validator: (value) {
                          if (value!.isEmpty) {
                            return 'Veuillez saisir votre nom';
                          }
                          return null;
                        },
                      ),
                      CheckboxListTile(
                        title: const Text('J\'accepte les CGU'),
                        value: _accepterCGU,
                        onChanged: (value) {
                          setState(() {
                            _accepterCGU = value!;
                          });
                        },
                      ),
                      ElevatedButton(
                        onPressed: () {
                          if (_formKey.currentState!.validate()) {
                            ScaffoldMessenger.of(context).showSnackBar(
                                const SnackBar(content: Text('Données en cours')));
                          }
                        },
                        child: const Text('Submit'),
                      ),
                    ],
                  ),
                ),
              ),
            );
          }
        }