[{"data":1,"prerenderedAt":76},["ShallowReactive",2],{"tutorial-slidable-e-swipe-to-action-nelle-liste-flutter-con-flutter-slidable":3,"comments-tutorial-slidable-e-swipe-to-action-nelle-liste-flutter-con-flutter-slidable":75},{"id":4,"title":5,"slug":6,"excerpt":7,"intro":8,"cover_image":9,"video_url":10,"difficulty":11,"estimated_minutes":12,"flutter_version":13,"status":14,"published_at":15,"meta_title":16,"meta_description":17,"category":18,"author":22,"steps":24},27,"Slidable e swipe-to-action nelle liste Flutter con flutter_slidable","slidable-e-swipe-to-action-nelle-liste-flutter-con-flutter-slidable","Impara ad aggiungere azioni scorrevoli agli elementi di una ListView in Flutter usando il pacchetto flutter_slidable: elimina, archivia e condividi con un semplice swipe.","## Introduzione\n\nLe liste sono ovunque nelle app moderne: email, chat, task list. Un pattern UX molto diffuso è quello di rivelare azioni contestuali (elimina, archivia, condividi) facendo scorrere lateralmente un elemento della lista.\n\nIn questo tutorial impareremo a usare il pacchetto [`flutter_slidable`](https:\u002F\u002Fpub.dev\u002Fpackages\u002Fflutter_slidable), la soluzione più diffusa e flessibile per implementare gli **swipe-to-action** in Flutter.\n\nAlla fine avremo una lista di attività in cui potremo scorrere ogni elemento verso sinistra o destra per rivelare pulsanti di azione, con animazioni fluide e comportamenti personalizzabili.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002F50e0f29e-d498-4140-97b4-5a5020cebeeb.jpg",null,"beginner",25,"3.x","published","2026-07-03T04:31:00+00:00","Swipe-to-action in Flutter con flutter_slidable","Guida pratica per aggiungere azioni scorrevoli alle liste Flutter con flutter_slidable: elimina, archivia e condividi con lo swipe.",{"id":19,"name":20,"slug":21},1,"Guide","guide",{"id":19,"name":23},"Flutter Bot",[25,32,40,47,54,61,68],{"id":26,"position":19,"title":27,"body":28,"code_snippet":29,"code_language":30,"expected_result":31,"demo_url":10,"video_url":10},182,"Aggiungere la dipendenza flutter_slidable","Per prima cosa aggiungiamo il pacchetto al nostro progetto. Apri il terminale nella cartella del progetto ed esegui il comando di installazione, oppure aggiungi manualmente la dipendenza nel file `pubspec.yaml`.\n\nDopo aver salvato, esegui `flutter pub get` per scaricare il pacchetto.","flutter pub add flutter_slidable\n\n# oppure in pubspec.yaml:\n# dependencies:\n#   flutter_slidable: ^3.1.0","bash","Il pacchetto flutter_slidable compare tra le dipendenze e viene scaricato correttamente.",{"id":33,"position":34,"title":35,"body":36,"code_snippet":37,"code_language":38,"expected_result":39,"demo_url":10,"video_url":10},183,2,"Preparare un modello dati e la lista di base","Creiamo un semplice modello `Task` e uno `StatefulWidget` che mostra una `ListView` di attività. Partiamo da una lista standard, senza ancora le azioni scorrevoli, per avere una base su cui lavorare.","import 'package:flutter\u002Fmaterial.dart';\n\nclass Task {\n  final String id;\n  final String title;\n  bool archived;\n\n  Task({required this.id, required this.title, this.archived = false});\n}\n\nclass TaskListPage extends StatefulWidget {\n  const TaskListPage({super.key});\n\n  @override\n  State\u003CTaskListPage> createState() => _TaskListPageState();\n}\n\nclass _TaskListPageState extends State\u003CTaskListPage> {\n  final List\u003CTask> _tasks = List.generate(\n    8,\n    (i) => Task(id: '$i', title: 'Attività numero ${i + 1}'),\n  );\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: const Text('Le mie attività')),\n      body: ListView.builder(\n        itemCount: _tasks.length,\n        itemBuilder: (context, index) {\n          final task = _tasks[index];\n          return ListTile(\n            leading: const Icon(Icons.task_alt),\n            title: Text(task.title),\n          );\n        },\n      ),\n    );\n  }\n}","dart","L'app mostra una lista con 8 attività statiche, senza interazioni di swipe.",{"id":41,"position":42,"title":43,"body":44,"code_snippet":45,"code_language":38,"expected_result":46,"demo_url":10,"video_url":10},184,3,"Avvolgere l'elemento con il widget Slidable","Ora avvolgiamo ogni `ListTile` in un widget `Slidable`. Ogni `Slidable` deve avere una `key` univoca. Aggiungiamo un `endActionPane` (che appare scorrendo da destra verso sinistra) con un'azione di eliminazione.\n\nRicordati di importare il pacchetto con `import 'package:flutter_slidable\u002Fflutter_slidable.dart';`.","import 'package:flutter_slidable\u002Fflutter_slidable.dart';\n\n\u002F\u002F dentro itemBuilder:\nreturn Slidable(\n  key: ValueKey(task.id),\n  endActionPane: ActionPane(\n    motion: const DrawerMotion(),\n    children: [\n      SlidableAction(\n        onPressed: (context) {\n          setState(() => _tasks.removeAt(index));\n        },\n        backgroundColor: Colors.red,\n        foregroundColor: Colors.white,\n        icon: Icons.delete,\n        label: 'Elimina',\n      ),\n    ],\n  ),\n  child: ListTile(\n    leading: const Icon(Icons.task_alt),\n    title: Text(task.title),\n  ),\n);","Scorrendo un elemento da destra verso sinistra compare un pulsante rosso 'Elimina' che rimuove l'attività dalla lista.",{"id":48,"position":49,"title":50,"body":51,"code_snippet":52,"code_language":38,"expected_result":53,"demo_url":10,"video_url":10},185,4,"Aggiungere azioni iniziali (startActionPane)","Oltre alle azioni finali, possiamo aggiungere azioni che appaiono scorrendo da sinistra verso destra tramite `startActionPane`. Aggiungiamo un'azione di **archiviazione** che modifica lo stato del task.\n\nOgni `ActionPane` supporta diverse animazioni tramite la proprietà `motion`: `DrawerMotion`, `BehindMotion`, `ScrollMotion` e `StretchMotion`. Prova a cambiarle per vedere l'effetto.","Slidable(\n  key: ValueKey(task.id),\n  startActionPane: ActionPane(\n    motion: const BehindMotion(),\n    children: [\n      SlidableAction(\n        onPressed: (context) {\n          setState(() => task.archived = !task.archived);\n        },\n        backgroundColor: Colors.blue,\n        foregroundColor: Colors.white,\n        icon: Icons.archive,\n        label: task.archived ? 'Ripristina' : 'Archivia',\n      ),\n    ],\n  ),\n  endActionPane: ActionPane(\n    motion: const DrawerMotion(),\n    children: [\n      SlidableAction(\n        onPressed: (context) {\n          setState(() => _tasks.removeAt(index));\n        },\n        backgroundColor: Colors.red,\n        foregroundColor: Colors.white,\n        icon: Icons.delete,\n        label: 'Elimina',\n      ),\n    ],\n  ),\n  child: ListTile(\n    leading: Icon(\n      task.archived ? Icons.inventory_2 : Icons.task_alt,\n      color: task.archived ? Colors.blue : null,\n    ),\n    title: Text(task.title),\n    subtitle: task.archived ? const Text('Archiviata') : null,\n  ),\n)","Scorrendo da sinistra verso destra appare un pulsante blu che archivia\u002Fripristina l'attività aggiornando l'icona e il sottotitolo.",{"id":55,"position":56,"title":57,"body":58,"code_snippet":59,"code_language":38,"expected_result":60,"demo_url":10,"video_url":10},186,5,"Abilitare la conferma con lo swipe completo (DismissiblePane)","Un'esperienza ancora più fluida consiste nel completare l'azione con uno swipe deciso, senza dover premere il pulsante. Basta assegnare un `DismissiblePane` all'`ActionPane`.\n\nÈ importante che il callback `onDismissed` esegua effettivamente la rimozione, altrimenti il widget resterebbe in uno stato incoerente. Mostriamo anche uno `SnackBar` per informare l'utente.","endActionPane: ActionPane(\n  motion: const DrawerMotion(),\n  dismissible: DismissiblePane(\n    onDismissed: () {\n      final removed = _tasks[index];\n      setState(() => _tasks.removeAt(index));\n      ScaffoldMessenger.of(context).showSnackBar(\n        SnackBar(content: Text('${removed.title} eliminata')),\n      );\n    },\n  ),\n  children: [\n    SlidableAction(\n      onPressed: (context) {\n        setState(() => _tasks.removeAt(index));\n      },\n      backgroundColor: Colors.red,\n      foregroundColor: Colors.white,\n      icon: Icons.delete,\n      label: 'Elimina',\n    ),\n  ],\n),","Uno swipe deciso verso sinistra elimina direttamente l'elemento e mostra una SnackBar di conferma.",{"id":62,"position":63,"title":64,"body":65,"code_snippet":66,"code_language":38,"expected_result":67,"demo_url":10,"video_url":10},187,6,"Gestire più azioni e chiudere gli altri Slidable","Possiamo inserire più `SlidableAction` nello stesso pane (ad esempio Condividi + Elimina) e usare `flex` per bilanciarne la larghezza. Inoltre, avvolgendo la lista in uno `SlidableAutoCloseBehavior`, quando apriamo un elemento gli altri si chiudono automaticamente, migliorando l'usabilità.","\u002F\u002F Avvolgi la ListView:\nbody: SlidableAutoCloseBehavior(\n  child: ListView.builder(\n    itemCount: _tasks.length,\n    itemBuilder: (context, index) {\n      \u002F\u002F ... i tuoi Slidable ...\n    },\n  ),\n),\n\n\u002F\u002F endActionPane con due azioni:\nendActionPane: ActionPane(\n  motion: const StretchMotion(),\n  children: [\n    SlidableAction(\n      flex: 1,\n      onPressed: (context) {\n        ScaffoldMessenger.of(context).showSnackBar(\n          const SnackBar(content: Text('Condivisione...')),\n        );\n      },\n      backgroundColor: Colors.green,\n      foregroundColor: Colors.white,\n      icon: Icons.share,\n      label: 'Condividi',\n    ),\n    SlidableAction(\n      flex: 1,\n      onPressed: (context) => setState(() => _tasks.removeAt(index)),\n      backgroundColor: Colors.red,\n      foregroundColor: Colors.white,\n      icon: Icons.delete,\n      label: 'Elimina',\n    ),\n  ],\n),","Ogni elemento mostra due azioni (Condividi ed Elimina) e aprendone uno gli altri Slidable già aperti si chiudono automaticamente.",{"id":69,"position":70,"title":71,"body":72,"code_snippet":73,"code_language":38,"expected_result":74,"demo_url":10,"video_url":10},188,7,"Rifiniture finali e best practice","## Conclusioni\n\nHai implementato una lista con azioni scorrevoli complete usando `flutter_slidable`. Ecco alcune buone pratiche da tenere a mente:\n\n- **Chiavi univoche**: assegna sempre una `key` stabile a ogni `Slidable`, soprattutto se gli elementi vengono riordinati o rimossi.\n- **Feedback all'utente**: usa `SnackBar` con azione *Annulla* per le operazioni distruttive come l'eliminazione.\n- **Coerenza dello stato**: aggiorna sempre la sorgente dati (`_tasks`) prima di far ricostruire la lista.\n- **Accessibilità**: le azioni via swipe non sono sempre scopribili; valuta di affiancare un menu contestuale (long press) per gli stessi comandi.\n- **`SlidableAutoCloseBehavior`**: mantiene l'interfaccia pulita chiudendo automaticamente gli elementi non attivi.\n\nCon questi accorgimenti la tua lista sarà professionale e piacevole da usare.","\u002F\u002F Esempio di SnackBar con azione Annulla\nvoid _deleteWithUndo(int index) {\n  final removed = _tasks[index];\n  setState(() => _tasks.removeAt(index));\n  ScaffoldMessenger.of(context).showSnackBar(\n    SnackBar(\n      content: Text('${removed.title} eliminata'),\n      action: SnackBarAction(\n        label: 'Annulla',\n        onPressed: () {\n          setState(() => _tasks.insert(index, removed));\n        },\n      ),\n    ),\n  );\n}","L'app permette di eliminare un'attività con possibilità di annullare l'operazione tramite la SnackBar.",[],1785219610051]