Based on @Bibek Saha's answer I am providing here another solution which makes the open/close state private to the CardCloseable class. There are one and a "half" disadvantages with this method versus a big advantage of blackboxing the CardCloseable's state and not needing to keep it with N variables for N Cards (or a Map) in the Dialog's onPressed():
StatefulWidget instead of state-less, so less efficient.CardCloseable class still rebuilds! But it builds an "invisible" SizedBox.shrink() widget and not a Card (see the logic in its build method). This can be improved if anyone can suggest what's the practice here because I could not find a way to return back from build a null widget, indicating not to bother with this widget. I am new to flutter.Here is my solution based on @Bibek Saha's:
import 'package:flutter/material.dart';
/// Flutter code sample for [Card].
void main() => runApp(const CardExampleApp());
class CardExampleApp extends StatelessWidget {
const CardExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Card Sample')),
body: MyExample(),
),
);
}
}
class MyExample extends StatelessWidget {
const MyExample({super.key});
@override
Widget build(BuildContext context) {
return ElevatedButton(
child: Text("press to show dialog"),
onPressed: () {
showDialog(
barrierDismissible: true,
barrierColor: Colors.red.withAlpha(90),
context: context,
builder: (BuildContext ctx) {
return Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.blueAccent, width: 2),
borderRadius: BorderRadius.circular(8.0),
),
child: Column(
children: [
CardCloseable(text: "item"),
CardCloseable(text: "another item"),
CardCloseable(text: "another item"),
],
),
);
},
);
},
);
}
}
class CardCloseable extends StatefulWidget {
final String text;
final double width;
// optionally, creator can supply extra callback for when closing
final VoidCallback? onClose;
const CardCloseable({
super.key,
required this.text,
this.onClose,
this.width = 200,
});
@override
State<CardCloseable> createState() => _CardCloseableState();
}
class _CardCloseableState extends State<CardCloseable> {
bool isOpen = true;
@override
void initState() {
isOpen = true;
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return isOpen
? SizedBox(
width: 200,
child: Card(
color: Color(0xFFCCAAAA),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
// TODO: this closes the whole map!!!
Align(
alignment: Alignment.topRight,
child: IconButton(
icon: Icon(Icons.close, color: Colors.red),
onPressed: () {
setState(() {
isOpen = false;
});
if (widget.onClose != null) {
widget.onClose!();
}
},
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Text(widget.text),
),
],
),
),
)
// if we are in a closed state, then return this:
// this is bad design
: SizedBox.shrink();
}
}
class MyCard extends StatelessWidget {
final String text;
const MyCard({super.key, required this.text});
@override
Widget build(BuildContext context) {
return Center(
child: Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[CloseButton(), Text("the contents: $text")],
),
),
);
}
}