↑
CHAPITRE 4.5

Dialogs, SnackBar et BottomSheet

Communiquer avec l'utilisateur et afficher des informations importantes
Une bonne application communique avec l'utilisateur. Dans ce chapitre, nous allons découvrir trois composants essentiels pour donner du feedback : les Dialogs pour les messages importants, les SnackBar pour les notifications discrètes, et les BottomSheet pour afficher des options ou des informations supplémentaires.

4.5Dialogs, SnackBar et BottomSheet dans Flutter

4.5.1 – Principes de feedback utilisateur

Le feedback utilisateur est essentiel pour une bonne expérience. Il permet à l'utilisateur de comprendre ce qui se passe dans l'application.

đź’¬ Pourquoi donner du feedback ?

Quand un utilisateur effectue une action, il doit savoir :

  • Si l'action a rĂ©ussi ou Ă©chouĂ©
  • Ce qui se passe actuellement (chargement, traitement...)
  • Quelles sont les prochaines Ă©tapes possibles
Exemple concret :
Si l'utilisateur clique sur "Supprimer", il doit savoir si la suppression a réussi. Sans feedback, l'utilisateur ne sait pas si son action a été prise en compte, ce qui crée de la confusion et de la frustration.

📊 Types de feedback

Flutter propose plusieurs moyens de communiquer avec l'utilisateur :

  • Dialog : Message important qui bloque l'interface jusqu'Ă  ce que l'utilisateur rĂ©ponde
  • SnackBar : Notification discrète en bas de l'Ă©cran qui disparaĂ®t automatiquement
  • BottomSheet : Panneau qui glisse depuis le bas pour afficher des options ou des informations

🎯 Quand utiliser chaque composant ?

Dialog :
Utilisez un Dialog pour :
  • Demander une confirmation avant une action importante (suppression, dĂ©connexion...)
  • Afficher une erreur critique qui nĂ©cessite l'attention de l'utilisateur
  • Demander des informations essentielles
Le Dialog bloque l'interface : l'utilisateur doit interagir avec lui avant de continuer.
SnackBar :
Utilisez une SnackBar pour :
  • Confirmer une action rĂ©ussie ("Message envoyĂ©", "DonnĂ©es sauvegardĂ©es")
  • Afficher une information non critique
  • Informer d'un changement d'Ă©tat
La SnackBar est discrète et ne bloque pas l'interface. Elle disparaît automatiquement après quelques secondes.
BottomSheet :
Utilisez un BottomSheet pour :
  • Afficher des options d'action (partager, modifier, supprimer...)
  • Montrer des informations supplĂ©mentaires sans changer d'Ă©cran
  • Proposer plusieurs choix Ă  l'utilisateur
Le BottomSheet glisse depuis le bas et peut être fermé en glissant vers le bas ou en cliquant en dehors.

💡 Règle d'or

Principe important :
Choisissez le bon composant selon l'importance du message :
  • Critique → Dialog (l'utilisateur doit absolument voir et rĂ©pondre)
  • Information → SnackBar (l'utilisateur peut continuer sans interagir)
  • Options → BottomSheet (l'utilisateur choisit parmi plusieurs actions)

4.5.2 – Dialogs

Un Dialog est une fenêtre modale qui s'affiche au-dessus de l'interface et bloque l'interaction jusqu'à ce que l'utilisateur réponde.

📝 Syntaxe

Voici comment afficher un Dialog :

// Afficher un Dialog
showDialog(
  context: context,
  builder: (context) {
    return AlertDialog(
      title: const Text('Titre du Dialog'),
      content: const Text('Message du Dialog'),
      actions: [
        TextButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: const Text('OK'),
        ),
      ],
    );
  },
);

// Fermer un Dialog
Navigator.pop(context);

// Fermer un Dialog et retourner une valeur
Navigator.pop(context, 'valeur');

Analysons cette syntaxe :

  • showDialog() : Fonction qui affiche un Dialog
  • context : Le contexte de l'application (nĂ©cessaire pour afficher le Dialog)
  • builder : Fonction qui construit le Dialog
  • AlertDialog : Widget qui crĂ©e un Dialog avec titre, contenu et actions
  • title : Le titre du Dialog (optionnel)
  • content : Le contenu principal du Dialog
  • actions : Liste des boutons d'action (gĂ©nĂ©ralement en bas du Dialog)
  • Navigator.pop(context) : Ferme le Dialog
  • Navigator.pop(context, valeur) : Ferme le Dialog et retourne une valeur
context :
Le paramètre context est nécessaire pour que Flutter sache où afficher le Dialog dans l'arbre des widgets. Vous l'obtenez automatiquement dans la méthode build().

đź§Ş Exemple : Dialog simple

Voici un exemple complet qui affiche un Dialog simple :

Exemple Dialog simple Flutter
L'utilisation de showDialog() pour afficher un Dialog simple.
import 'package:flutter/material.dart';

void main() {
  runApp(const MaPage());
}

class MaPage extends StatelessWidget {
  const MaPage({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Dialogs'),
      ),
      body: SafeArea(
        child: Center(
          child: ElevatedButton(
            onPressed: () {
              showDialog(
                context: context,
                builder: (context) {
                  return AlertDialog(
                    title: const Text('Titre du Dialog'),
                    content: const Text('Message du Dialog'),
                    actions: [
                      TextButton(
                        onPressed: () {
                          Navigator.pop(context);
                        },
                        child: const Text('OK'),
                      ),
                    ],
                  );
                },
              );
            },
            child: const Text('Afficher un Dialog'),
          ),
        ),
      ),
    );
  }
}

Dans cet exemple :

  • Un bouton affiche un Dialog quand on clique dessus
  • Le Dialog contient un titre, un message et un bouton "OK"
  • Quand on clique sur "OK", le Dialog se ferme avec Navigator.pop(context)

âś… Dialog de confirmation

Un Dialog de confirmation permet de demander à l'utilisateur de confirmer une action avant de l'exécuter.

📝 Syntaxe

Voici la syntaxe pour un Dialog de confirmation :

showDialog(
  context: context,
  builder: (context) {
    return AlertDialog(
      title: const Text('Confirmer la suppression'),
      content: const Text('Êtes-vous sûr de vouloir supprimer cet élément ?'),
      actions: [
        TextButton(
          onPressed: () {
            Navigator.pop(context); // Annuler
          },
          child: const Text('Annuler'),
        ),
        ElevatedButton(
          onPressed: () {
            Navigator.pop(context); // Fermer le Dialog
            // Exécuter l'action ici
          },
          child: const Text('Supprimer'),
        ),
      ],
    );
  },
);
Qu’avons-nous ajoutĂ© par rapport au dialog simple ?
La seule vraie différence est l’ajout d’un ElevatedButton pour l’action “Supprimer”.
Dans un dialog simple, il n’y avait qu’un seul bouton “OK”. Ici :
  • On garde le bouton “Annuler” (avec TextButton, une alternative frĂ©quente Ă  un bouton “OK”).
  • On ajoute un bouton Supprimer (avec ElevatedButton) qui permet de dĂ©clencher l’action de confirmation (par exemple, supprimer l’élĂ©ment).
👉 C’est donc bien l’ajout du ElevatedButton (pour la confirmation) qui distingue ce Dialog de confirmation d’un dialog simple à un seul bouton.

đź§Ş Exemple : Dialog de confirmation

Voici un exemple complet avec un bouton qui affiche un Dialog de confirmation :

Exemple Dialog de confirmation Flutter
L'utilisation de showDialog() pour afficher un Dialog de confirmation.
import 'package:flutter/material.dart';

void main() {
  runApp(const MaPage());
}

class MaPage extends StatelessWidget {
  const MaPage({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Confirmation'),
      ),
      body: SafeArea(
        child: Center(
          child: ElevatedButton(
            onPressed: () {
              showDialog(
                context: context,
                builder: (context) {
                  return AlertDialog(
                    title: const Text('Confirmer la suppression'),
                    content: const Text('Êtes-vous sûr de vouloir supprimer cet élément ?'),
                    actions: [
                      TextButton(
                        onPressed: () {
                          Navigator.pop(context); // Annuler
                        },
                        child: const Text('Annuler'),
                      ),
                      ElevatedButton(
                        onPressed: () {
                          Navigator.pop(context); // Fermer le Dialog
                          // Ici, vous pouvez exécuter l'action de suppression
                          print('Élément supprimé');
                        },
                        child: const Text('Supprimer'),
                      ),
                    ],
                  );
                },
              );
            },
            child: const Text('Supprimer'),
          ),
        ),
      ),
    );
  }
}

Dans cet exemple :

  • Le Dialog propose deux actions : "Annuler" et "Supprimer"
  • Si l'utilisateur clique sur "Annuler", le Dialog se ferme sans rien faire
  • Si l'utilisateur clique sur "Supprimer", le Dialog se ferme et l'action est exĂ©cutĂ©e
  • L'utilisateur doit choisir avant de continuer

📝 Dialog avec retour de valeur

Un Dialog peut retourner une valeur quand il est fermé, permettant à l'écran qui l'a ouvert de savoir quelle action l'utilisateur a choisie.

📝 Syntaxe

Voici la syntaxe pour un Dialog qui retourne une valeur :

// Afficher un Dialog et attendre le résultat
final resultat = await showDialog(
  context: context,
  builder: (context) {
    return AlertDialog(
      title: const Text('Choisir une option'),
      content: const Text('Que voulez-vous faire ?'),
      actions: [
        TextButton(
          onPressed: () {
            Navigator.pop(context, 'option1'); // Retourner 'option1'
          },
          child: const Text('Option 1'),
        ),
        TextButton(
          onPressed: () {
            Navigator.pop(context, 'option2'); // Retourner 'option2'
          },
          child: const Text('Option 2'),
        ),
      ],
    );
  },
);

// Utiliser le résultat
if (resultat != null) {
  print('L\'utilisateur a choisi : $resultat');
}

Analysons cette syntaxe :

  • await showDialog() : Attend que le Dialog soit fermĂ©
  • Navigator.pop(context, 'option1') : Ferme le Dialog et retourne une valeur
  • resultat : Contient la valeur retournĂ©e (ou null si fermĂ© sans valeur)
Retour de valeur :
Le deuxième paramètre de Navigator.pop() est la valeur retournée. Si l'utilisateur ferme le Dialog en cliquant en dehors ou en appuyant sur retour, resultat sera null.

đź§Ş Exemple : Dialog avec retour de valeur

Voici un exemple complet oĂą un Dialog retourne le choix de l'utilisateur :

Exemple Dialog avec retour de valeur Flutter
L'utilisation de showDialog() pour afficher un Dialog avec retour de valeur.
import 'package:flutter/material.dart';

void main() {
  runApp(const MaPage());
}

class MaPage extends StatelessWidget {
  const MaPage({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  String? choixUtilisateur;

  Future<void> afficherDialogAvecRetour() async {
    final resultat = await showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: const Text('Choisir une option'),
          content: const Text('Que voulez-vous faire ?'),
          actions: [
            TextButton(
              onPressed: () {
                Navigator.pop(context, 'option1'); // Retourner 'option1'
              },
              child: const Text('Option 1'),
            ),
            TextButton(
              onPressed: () {
                Navigator.pop(context, 'option2'); // Retourner 'option2'
              },
              child: const Text('Option 2'),
            ),
          ],
        );
      },
    );

    if (resultat != null) {
      setState(() {
        choixUtilisateur = resultat as String;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Dialog avec retour'),
      ),
      body: SafeArea(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: afficherDialogAvecRetour,
                child: const Text('Afficher le Dialog'),
              ),
              if (choixUtilisateur != null) ...[
                const SizedBox(height: 20),
                Text(
                  'Vous avez choisi : $choixUtilisateur',
                  style: const TextStyle(fontSize: 18),
                ),
              ],
            ],
          ),
        ),
      ),
    );
  }
}

Dans cet exemple :

  • Le bouton affiche un Dialog avec deux options
  • Chaque option retourne une valeur diffĂ©rente avec Navigator.pop(context, valeur)
  • La valeur retournĂ©e est stockĂ©e dans choixUtilisateur et affichĂ©e Ă  l'Ă©cran
  • Si l'utilisateur ferme le Dialog sans choisir, resultat sera null

⚠️ Dialog d'erreur

void afficherErreur(String message) {
  showDialog(
    context: context,
    builder: (context) {
      return AlertDialog(
        title: const Text('Erreur'),
        content: Text(message),
        actions: [
          ElevatedButton(
            onPressed: () {
              Navigator.pop(context);
            },
            child: const Text('OK'),
          ),
        ],
      );
    },
  );
}

Un Dialog d'erreur informe l'utilisateur qu'un problème s'est produit.

💡 Points clés à retenir

  • Un Dialog bloque l'interface jusqu'Ă  ce que l'utilisateur rĂ©ponde
  • Utilisez showDialog() pour afficher un Dialog
  • AlertDialog est le widget de base pour crĂ©er un Dialog
  • Utilisez Navigator.pop(context) pour fermer le Dialog
  • Un Dialog peut retourner une valeur avec Navigator.pop(context, valeur)
  • Utilisez les Dialogs pour les messages importants qui nĂ©cessitent une rĂ©ponse

4.5.3 – SnackBar

Une SnackBar est une notification discrète qui s'affiche en bas de l'écran et disparaît automatiquement après quelques secondes.

📝 Syntaxe

Voici comment afficher une SnackBar :

// Afficher une SnackBar simple
ScaffoldMessenger.of(context).showSnackBar(
  const SnackBar(
    content: Text('Message affiché dans la SnackBar'),
  ),
);

// SnackBar avec durée personnalisée
ScaffoldMessenger.of(context).showSnackBar(
  SnackBar(
    content: const Text('Message personnalisé'),
    duration: const Duration(seconds: 5),
  ),
);

// SnackBar avec action
ScaffoldMessenger.of(context).showSnackBar(
  SnackBar(
    content: const Text('Élément supprimé'),
    action: SnackBarAction(
      label: 'Annuler',
      onPressed: () {
        // Action à exécuter
      },
    ),
  ),
);

// SnackBar avec couleur personnalisée
ScaffoldMessenger.of(context).showSnackBar(
  SnackBar(
    content: const Text('Message d\'erreur'),
    backgroundColor: Colors.red,
  ),
);

Analysons cette syntaxe :

  • ScaffoldMessenger.of(context) : Obtient le gestionnaire de SnackBar
  • showSnackBar() : Affiche la SnackBar
  • SnackBar : Widget qui crĂ©e la notification
  • content : Le contenu de la SnackBar (gĂ©nĂ©ralement un Text)
  • duration : DurĂ©e d'affichage (par dĂ©faut 4 secondes)
  • action : Bouton d'action optionnel
  • backgroundColor : Couleur de fond de la SnackBar
ScaffoldMessenger :
ScaffoldMessenger est le système qui gère l'affichage des SnackBar dans Flutter. Il est automatiquement disponible dans un Scaffold. Vous devez utiliser ScaffoldMessenger.of(context) pour obtenir son instance.

đź§Ş Exemple : SnackBar simple

Voici un exemple complet qui affiche une SnackBar simple :

Exemple SnackBar simple Flutter
L'utilisation de ScaffoldMessenger.of(context).showSnackBar() pour afficher une SnackBar simple.
import 'package:flutter/material.dart';

void main() {
  runApp(const MaPage());
}

class MaPage extends StatelessWidget {
  const MaPage({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('SnackBar'),
      ),
      body: SafeArea(
        child: Center(
          child: ElevatedButton(
            onPressed: () {
              ScaffoldMessenger.of(context).showSnackBar(
                const SnackBar(
                  content: Text('Message affiché dans la SnackBar'),
                ),
              );
            },
            child: const Text('Afficher une SnackBar'),
          ),
        ),
      ),
    );
  }
}

Dans cet exemple :

  • Un bouton affiche une SnackBar quand on clique dessus
  • La SnackBar s'affiche en bas de l'Ă©cran avec le message
  • La SnackBar disparaĂ®t automatiquement après 4 secondes
ScaffoldMessenger :
ScaffoldMessenger est le système qui gère l'affichage des SnackBar dans Flutter. Il est automatiquement disponible dans un Scaffold. Vous devez utiliser ScaffoldMessenger.of(context) pour obtenir son instance.

⏱️ SnackBar avec durée personnalisée

ScaffoldMessenger.of(context).showSnackBar(
  SnackBar(
    content: const Text('Message personnalisé'),
    duration: const Duration(seconds: 5), // Afficher pendant 5 secondes
  ),
);

Par défaut, une SnackBar disparaît après 4 secondes. Vous pouvez changer cette durée avec le paramètre duration.

🎨 SnackBar avec action

Une SnackBar peut contenir un bouton d'action :

Exemple SnackBar avec action Flutter
L'utilisation de ScaffoldMessenger.of(context).showSnackBar() pour afficher une SnackBar avec action.
ScaffoldMessenger.of(context).showSnackBar(
  SnackBar(
    content: const Text('Élément supprimé'),
    action: SnackBarAction(
      label: 'Annuler',
      onPressed: () {
        print('Action annulée');
        // Ici, vous pouvez annuler l'action précédente
      },
    ),
  ),
);

Analysons ce code :

  • action : Paramètre qui ajoute un bouton d'action
  • SnackBarAction : Widget qui crĂ©e le bouton d'action
  • label : Le texte du bouton
  • onPressed : Action Ă  exĂ©cuter quand le bouton est pressĂ©

âś… SnackBar de confirmation

Exemple SnackBar avec background Flutter
L'utilisation de ScaffoldMessenger.of(context).showSnackBar() pour afficher une SnackBar avec background.
ElevatedButton(
  onPressed: () {
    // Exécuter une action
    print('Action effectuée');
    
    // Afficher une confirmation
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(
        content: Text('Action réussie !'),
        backgroundColor: Colors.green,
      ),
    );
  },
  child: const Text('Effectuer une action'),
)

Une SnackBar de confirmation informe l'utilisateur qu'une action a réussi. Vous pouvez changer la couleur avec backgroundColor.

❌ SnackBar d'erreur

void afficherErreurSnackBar(String message) {
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(
      content: Text(message),
      backgroundColor: Colors.red,
      duration: const Duration(seconds: 5),
    ),
  );
}

Une SnackBar d'erreur utilise généralement une couleur rouge pour attirer l'attention.

💡 Points clés à retenir

  • Une SnackBar est une notification discrète qui ne bloque pas l'interface
  • Utilisez ScaffoldMessenger.of(context).showSnackBar() pour afficher une SnackBar
  • Une SnackBar disparaĂ®t automatiquement après quelques secondes (4 secondes par dĂ©faut)
  • Vous pouvez ajouter une action avec le paramètre action
  • Utilisez les SnackBar pour les messages non critiques qui ne nĂ©cessitent pas d'interaction
  • Changez la couleur avec backgroundColor pour indiquer le type de message
SnackBar vs Dialog :
  • SnackBar : Message informatif, disparaĂ®t automatiquement, ne bloque pas
  • Dialog : Message important, nĂ©cessite une rĂ©ponse, bloque l'interface
Utilisez une SnackBar pour "Message envoyé", un Dialog pour "Confirmer la suppression".

4.5.4 – BottomSheet

Un BottomSheet est un panneau qui glisse depuis le bas de l'écran pour afficher des options ou des informations supplémentaires.

📝 Syntaxe

Voici comment afficher un BottomSheet :

// BottomSheet modal (bloque l'interface)
showModalBottomSheet(
  context: context,
  builder: (context) {
    return Container(
      padding: const EdgeInsets.all(20),
      child: const Text('Contenu du BottomSheet'),
    );
  },
);

// BottomSheet avec hauteur personnalisée
showModalBottomSheet(
  context: context,
  builder: (context) {
    return Container(
      height: 300, // Hauteur fixe
      padding: const EdgeInsets.all(20),
      child: const Text('Contenu du BottomSheet'),
    );
  },
);

// BottomSheet avec coins arrondis
showModalBottomSheet(
  context: context,
  shape: const RoundedRectangleBorder(
    borderRadius: BorderRadius.vertical(
      top: Radius.circular(20),
    ),
  ),
  builder: (context) {
    return Container(
      padding: const EdgeInsets.all(20),
      child: const Text('BottomSheet avec coins arrondis'),
    );
  },
);

// Fermer un BottomSheet
Navigator.pop(context);

Analysons cette syntaxe :

  • showModalBottomSheet() : Affiche un BottomSheet modal (bloque l'interface)
  • context : Le contexte de l'application (nĂ©cessaire pour afficher le BottomSheet)
  • builder : Fonction qui construit le contenu du BottomSheet
  • height : Hauteur fixe du BottomSheet (optionnel)
  • shape : Forme personnalisĂ©e du BottomSheet (pour arrondir les coins)
  • Navigator.pop(context) : Ferme le BottomSheet
BottomSheet modal :
showModalBottomSheet() affiche un BottomSheet qui bloque l'interface. L'utilisateur doit fermer le BottomSheet (en glissant vers le bas ou en appuyant sur retour) avant de pouvoir continuer à interagir avec le reste de l'application. C'est la méthode recommandée pour afficher des options ou des actions importantes.

đź§Ş Exemple : BottomSheet simple

Voici un exemple complet qui affiche un BottomSheet simple :

Exemple BottomSheet simple Flutter
L'utilisation de showModalBottomSheet() pour afficher un BottomSheet simple.
import 'package:flutter/material.dart';

void main() {
  runApp(const MaPage());
}

class MaPage extends StatelessWidget {
  const MaPage({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('BottomSheet'),
      ),
      body: SafeArea(
        child: Center(
          child: ElevatedButton(
            onPressed: () {
              showModalBottomSheet(
                context: context,
                builder: (context) {
                  return Container(
                    padding: const EdgeInsets.all(20),
                    child: const Text('Contenu du BottomSheet'),
                  );
                },
              );
            },
            child: const Text('Afficher un BottomSheet'),
          ),
        ),
      ),
    );
  }
}

Dans cet exemple :

  • Un bouton affiche un BottomSheet quand on clique dessus
  • Le BottomSheet glisse depuis le bas de l'Ă©cran
  • Le BottomSheet contient un texte simple dans un Container
  • L'utilisateur peut fermer le BottomSheet en glissant vers le bas ou en appuyant sur retour

📝 BottomSheet avec options

Un BottomSheet est souvent utilisé pour afficher des options d'action :

Exemple BottomSheet avec options Flutter
L'utilisation de showModalBottomSheet() pour afficher un BottomSheet avec options.
void afficherOptions() {
  showModalBottomSheet(
    context: context,
    builder: (context) {
      return Container(
        padding: const EdgeInsets.all(20),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            ListTile(
              leading: const Icon(Icons.share),
              title: const Text('Partager'),
              onTap: () {
                Navigator.pop(context);
                print('Partager');
              },
            ),
            ListTile(
              leading: const Icon(Icons.edit),
              title: const Text('Modifier'),
              onTap: () {
                Navigator.pop(context);
                print('Modifier');
              },
            ),
            ListTile(
              leading: const Icon(Icons.delete),
              title: const Text('Supprimer'),
              onTap: () {
                Navigator.pop(context);
                print('Supprimer');
              },
            ),
          ],
        ),
      );
    },
  );
}

Analysons ce code :

  • Column : Organise les options verticalement
  • mainAxisSize: MainAxisSize.min : La colonne prend seulement l'espace nĂ©cessaire
  • ListTile : Widget qui crĂ©e une ligne avec icĂ´ne, titre et action
  • leading : Widget affichĂ© au dĂ©but (gĂ©nĂ©ralement une icĂ´ne)
  • onTap : Action Ă  exĂ©cuter quand la ligne est pressĂ©e

📏 BottomSheet avec hauteur personnalisée

showModalBottomSheet(
  context: context,
  builder: (context) {
    return Container(
      height: 300, // Hauteur fixe
      padding: const EdgeInsets.all(20),
      child: const Text('Contenu du BottomSheet'),
    );
  },
);

Vous pouvez définir une hauteur fixe avec height, ou laisser le BottomSheet s'adapter au contenu.

🎨 BottomSheet arrondi

showModalBottomSheet(
  context: context,
  shape: const RoundedRectangleBorder(
    borderRadius: BorderRadius.vertical(
      top: Radius.circular(20),
    ),
  ),
  builder: (context) {
    return Container(
      padding: const EdgeInsets.all(20),
      child: const Text('BottomSheet avec coins arrondis'),
    );
  },
);

Le paramètre shape permet de personnaliser la forme du BottomSheet, notamment pour arrondir les coins supérieurs.

💡 Points clés à retenir

  • Un BottomSheet glisse depuis le bas de l'Ă©cran
  • Utilisez showModalBottomSheet() pour un BottomSheet modal
  • Le BottomSheet peut contenir n'importe quel widget
  • Utilisez ListTile pour crĂ©er des listes d'options
  • Fermez le BottomSheet avec Navigator.pop(context)
  • Utilisez les BottomSheet pour afficher des options ou des informations supplĂ©mentaires
  • Personnalisez la forme avec shape et la hauteur avec height

4.5.5 – Choisir le bon composant de feedback

Choisir le bon composant selon la situation est essentiel pour une bonne expérience utilisateur.

📊 Tableau comparatif

Composant Quand l'utiliser Bloque l'interface ? Disparaît automatiquement ?
Dialog Confirmation, erreur critique, demande d'information importante Oui Non
SnackBar Confirmation d'action, information non critique Non Oui (4 secondes)
BottomSheet Options d'action, informations supplémentaires Oui (modal) ou Non Non

🎯 Exemples d'utilisation

Exemple 1 : Supprimer un élément
  • Dialog : "ĂŠtes-vous sĂ»r de vouloir supprimer ?" (demande de confirmation)
  • SnackBar : "ÉlĂ©ment supprimĂ©" (confirmation après suppression)
Exemple 2 : Partager du contenu
  • BottomSheet : Afficher les options (Partager sur Facebook, Twitter, Email...)
  • SnackBar : "Contenu partagĂ©" (confirmation après partage)
Exemple 3 : Erreur de connexion
  • Dialog : "Erreur de connexion. VĂ©rifiez votre connexion Internet." (erreur critique)
  • SnackBar : "Connexion perdue" (information non bloquante)

âś… Bonnes pratiques

  • Ne pas abuser des Dialogs : Ils bloquent l'interface, utilisez-les seulement pour les cas importants
  • Utiliser les SnackBar pour les confirmations : Elles sont discrètes et n'interrompent pas le flux
  • BottomSheet pour les options : IdĂ©al pour afficher plusieurs choix sans changer d'Ă©cran
  • Messages clairs et concis : L'utilisateur doit comprendre rapidement le message
  • CohĂ©rence : Utilisez toujours le mĂŞme type de composant pour le mĂŞme type de message

💡 Règle de décision rapide

Guide rapide :
  1. L'utilisateur doit absolument répondre ? → Dialog
  2. Je veux juste informer l'utilisateur ? → SnackBar
  3. Je veux proposer plusieurs options ? → BottomSheet
Résumé :
Choisissez le composant selon l'importance et le type de message :
  • Dialog = Important, nĂ©cessite une rĂ©ponse
  • SnackBar = Information, discrète
  • BottomSheet = Options, choix multiples
Félicitations ! 🎉
Vous avez terminé ce chapitre ! Vous savez maintenant :
  • âś… Quand et comment utiliser les Dialogs
  • âś… Afficher des notifications discrètes avec les SnackBar
  • âś… Proposer des options avec les BottomSheet
  • âś… Choisir le bon composant selon la situation
Vous pouvez maintenant communiquer efficacement avec vos utilisateurs ! đź’Ş