Action avec un swip grâce au widget Flutter Dismissible


Avatar de Pierre Courtois

Supprimer facilement les éléments d’une liste grâce au widget Dimissible. Dans ce guide, je vous explique très rapidement comment le mettre en place et le personnaliser selon vos besoins.


Widget dismissible

À quoi sert le widget Dismissible ?

Le widget Dismissible permet d’ajouter une interaction de balayage (swipe) sur un élément de l’interface utilisateur, généralement pour le supprimer ou effectuer une action spécifique. Vous pouvez par exemple l’utiliser dans une liste pour permettre aux utilisateurs de supprimer un élément d’un simple geste.

Pour vous donner quelques cas concrets, vous pouvez l’utiliser pour :

  • Suppression d’un élément d’une liste (ex: une tâche dans une application de gestion de tâches).
  • Archivage d’un message dans une boîte de réception.
  • Déplacement d’un élément vers une autre catégorie (ex: glisser un email vers « Lu » ou « Non lu »).
  • Activation d’une action rapide (ex: marquer un élément comme favori).

Comment mettre en place le widget Dismissible

Je vais vous montrer deux manières de mettre en place ce widget, pour une liste codée en brut, ou bien créée à partir d’un document Firebase.

ListView avec des éléments en dur (hardcodé)

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DismissibleListScreen(),
    );
  }
}

class DismissibleListScreen extends StatefulWidget {
  @override
  _DismissibleListScreenState createState() => _DismissibleListScreenState();
}

class _DismissibleListScreenState extends State<DismissibleListScreen> {
  List<String> items = ["Item 1", "Item 2", "Item 3", "Item 4"];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Dismissible List")),
      body: ListView.builder(
        itemCount: items.length,
        itemBuilder: (context, index) {
          final item = items[index];
          return Dismissible(
            key: Key(item),
            onDismissed: (direction) {
              setState(() {
                items.removeAt(index);
              });
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text("$item supprimé")),
              );
            },
            background: Container(color: Colors.red),
            child: ListTile(title: Text(item)),
          );
        },
      ),
    );
  }
}

Ici, chaque élément de ma liste est construit à partir d’un widget Dismissible, ce qui me permet de le retirer en swippant dessus.

ListView avec des données venant de Firebase

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

class FirebaseDismissibleList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Dismissible avec Firebase")),
      body: StreamBuilder(
        stream: FirebaseFirestore.instance.collection('tasks').snapshots(),
        builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
          if (!snapshot.hasData) return Center(child: CircularProgressIndicator());

          return ListView(
            children: snapshot.data!.docs.map((doc) {
              return Dismissible(
                key: Key(doc.id),
                onDismissed: (direction) {
              //Supprime le document de Firebase
              FirebaseFirestore.instance.collection('tasks').doc(doc.id).delete();
                },
                background: Container(color: Colors.red),
                child: ListTile(title: Text(doc['title'])),
              );
            }).toList(),
          );
        },
      ),
    );
  }
}

De la même manière, chaque élément de ma liste est encapsulé dans un Dimissible, ce qui va me permettre de le retirer en swippant. Dans le même temps, l’élément est aussi supprimé de Firebase.

Personnalisation du widget Dismissible

Voici quelques manières de personnaliser votre Dismissible, selon vos besoins.

Modifier la durée de l’animation

Il est possible de contrôler le temps que met votre item à disparaitre en utilisant la propriété resizeDuration :

resizeDuration: Duration(milliseconds: 300),

Modifier les actions selon la direction du swipe

Il est possible d’effectuer une action différente selon le sens du swipe, de la manière suivante :

onDismissed: (direction) {
  if (direction == DismissDirection.startToEnd) {
    print("Archiver");
  } else {
    print("Supprimer");
  }
},

Ajouter une confirmation avant suppression

Pour plus de sécurité, vous pouvez aussi afficher un message de confirmation avant de supprimer l’item, grâce la propriété confirmDismiss :

confirmDismiss: (direction) async {
  return await showDialog(
    context: context,
    builder: (context) => AlertDialog(
      title: Text("Confirmer"),
      content: Text("Voulez-vous vraiment supprimer cet élément ?"),
      actions: [
        TextButton(onPressed: () => Navigator.of(context).pop(false), child: Text("Non")),
        TextButton(onPressed: () => Navigator.of(context).pop(true), child: Text("Oui")),
      ],
    ),
  );
},
Avatar de Pierre Courtois