I'm building a simple listView in Flutter where the "cells" are simple Cards with a set margin. When dismissing these cards, the "margin" covers the dismissible-background resulting in ugly designs. I've created a sample-app to showcase this problem:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
// MyApp is a StatefulWidget. This allows updating the state of the
// widget when an item is removed.
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
@override
MyAppState createState() {
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
final items = List<String>.generate(20, (i) => "Item ${i + 1}");
@override
Widget build(BuildContext context) {
final title = 'Dismissing Items';
return MaterialApp(
title: title,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return Dismissible(
// Each Dismissible must contain a Key. Keys allow Flutter to
// uniquely identify widgets.
key: Key(item),
// Provide a function that tells the app
// what to do after an item has been swiped away.
onDismissed: (direction) {
// Remove the item from the data source.
setState(() {
items.removeAt(index);
});
// Then show a snackbar.
Scaffold.of(context)
.showSnackBar(SnackBar(content: Text("$item dismissed")));
},
// Show a red background as the item is swiped away.
background: Container(color: Colors.red),
child: Card(color: Colors.blue, margin: EdgeInsets.all(9), child: ListTile(title: Text('$item'))),
);
},
),
),
);
}
}
This results in the following design when dismissing:
It's also not possible to put the dismissible into the card, since you don't swipe the card away then. Is this a bug in Flutter or is there an easier solution?
first try to wrap Dismissible with another widget so that the space around them remains for example with Padding
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(
left: 16,
right: 16,
),
child: Dismissible(...),
);
}
}
then we implement the internal part of our Dismissible widget, add a container that will be rendered when we swipe our element, and don’t forget to render the element itself that we will swipe
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(
left: 16,
right: 16,
),
child: Dismissible(
key: ValueKey(id),
background: Container(
// most importantly, do not forget to give the inner container a
// padding to the right so that our icon does not stick to the
// wall of the container when swiping
padding: const EdgeInsets.only(
right: 16,
),
color: Theme.of(context).colorScheme.error,
alignment: Alignment.centerRight,
child: const Icon(
Icons.delete,
color: Colors.white,
),
),
child: Card(
// also if you use a card as an element that will swipe then
// you need to remove its default space
margin: const EdgeInsets.all(0),
child: ListTile(...),
),
);
}
}
hope this helps!)