skills/flutter/references/widgets-dismissible.md

4.0 KiB

name description
widgets-dismissible Flutter Dismissible - swipe-to-dismiss widgets with callbacks

Dismissible

Dismissible allows widgets to be dismissed by swiping.

Basic Usage

Dismissible(
  key: Key(item.id),
  onDismissed: (direction) {
    // Handle dismissal
    setState(() {
      items.remove(item);
    });
  },
  child: ListTile(title: Text(item.name)),
)

Dismiss Directions

Dismissible(
  key: Key(item.id),
  direction: DismissDirection.horizontal, // horizontal, vertical, endToStart, startToEnd, up, down, all
  onDismissed: (direction) {
    if (direction == DismissDirection.endToStart) {
      // Swiped left
    } else {
      // Swiped right
    }
  },
  child: ListTile(title: Text(item.name)),
)

Background

Show background when dismissing.

Dismissible(
  key: Key(item.id),
  background: Container(
    color: Colors.red,
    alignment: Alignment.centerLeft,
    padding: EdgeInsets.only(left: 20),
    child: Icon(Icons.delete, color: Colors.white),
  ),
  secondaryBackground: Container(
    color: Colors.green,
    alignment: Alignment.centerRight,
    padding: EdgeInsets.only(right: 20),
    child: Icon(Icons.archive, color: Colors.white),
  ),
  onDismissed: (direction) {
    if (direction == DismissDirection.endToStart) {
      // Delete
    } else {
      // Archive
    }
  },
  child: ListTile(title: Text(item.name)),
)

Confirm Dismissal

Dismissible(
  key: Key(item.id),
  confirmDismiss: (direction) async {
    // Show confirmation dialog
    return await showDialog<bool>(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('Confirm'),
        content: Text('Delete this item?'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context, false),
            child: Text('Cancel'),
          ),
          ElevatedButton(
            onPressed: () => Navigator.pop(context, true),
            child: Text('Delete'),
          ),
        ],
      ),
    ) ?? false;
  },
  onDismissed: (direction) {
    // Handle dismissal
  },
  child: ListTile(title: Text(item.name)),
)

Complete Example

ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    final item = items[index];
    return Dismissible(
      key: Key(item.id),
      direction: DismissDirection.endToStart,
      background: Container(
        color: Colors.red,
        alignment: Alignment.centerRight,
        padding: EdgeInsets.only(right: 20),
        child: Icon(Icons.delete, color: Colors.white),
      ),
      confirmDismiss: (direction) async {
        return await showDialog<bool>(
          context: context,
          builder: (context) => AlertDialog(
            title: Text('Delete?'),
            content: Text('Are you sure?'),
            actions: [
              TextButton(
                onPressed: () => Navigator.pop(context, false),
                child: Text('Cancel'),
              ),
              ElevatedButton(
                onPressed: () => Navigator.pop(context, true),
                child: Text('Delete'),
              ),
            ],
          ),
        ) ?? false;
      },
      onDismissed: (direction) {
        setState(() {
          items.removeAt(index);
        });
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Item deleted')),
        );
      },
      child: ListTile(title: Text(item.name)),
    );
  },
)

Key Points

  • Use Dismissible for swipe-to-dismiss
  • Provide unique key for each item
  • Use background and secondaryBackground for visual feedback
  • Use confirmDismiss to confirm before dismissing
  • Handle onDismissed to update state
  • Set direction to control swipe directions
  • Works well in ListView.builder
  • Update list after dismissal