Reputation: 727
I would like to achieve similar things in Google Keep.
How can I enable multiple selections on long press and change the header buttons, so that I can delete those selected items later?
My current Dart code :
@override
Widget build(BuildContext context) {
return new Card(
child: new Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
new ListTile(
leading: const Icon(Icons.info),
title: new Text(item.name),
subtitle: new Text(item.description),
trailing: new Text(item.dateTime.month.toString()),
onTap: () => _openEditDialog(context, item),
onLongPress: // what should I put here,
)
]),
);
}
Upvotes: 17
Views: 20788
Reputation: 51
I made a similar implementation a couple of days ago. Long-press on any item in the list to activate the selection, then single-tap to select afterwards. Once the desired items have been selected, tap the delete button to remove all selected items from the list.
CODE:
import 'package:flutter/material.dart';
void main() => runApp(const MultiSelect());
class MultiSelect extends StatefulWidget {
const MultiSelect({super.key});
@override
State<MultiSelect> createState() => _MultiSelectState();
}
class _MultiSelectState extends State<MultiSelect> {
existsInTrashCan(Course course) => trashCan.contains(course);
List<Course> trashCan = [];
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
brightness: Brightness.dark,
colorSchemeSeed: Colors.cyan.shade900,
useMaterial3: true,
),
home: Scaffold(
appBar: trashCan.isEmpty
? AppBar(
title: const Text('Multi-Delete'),
centerTitle: true,
backgroundColor: Colors.grey.shade900,
)
: AppBar(
backgroundColor: Colors.grey.shade800,
leading: IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
setState(() {
trashCan.clear();
});
},
),
title: Text(trashCan.length.toString()),
actions: [
IconButton(
onPressed: () {
coursesData
.removeWhere((item) => trashCan.contains(item));
trashCan.clear();
setState(() {});
},
icon: const Icon(Icons.delete))
],
),
body: ListView(
children: [
const SizedBox(height: 30),
ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: coursesData.length,
separatorBuilder: (context, index) => const SizedBox(height: 5),
itemBuilder: (BuildContext context, int index) {
return PrettyCard(
name: coursesData[index].name,
isSelected: existsInTrashCan(coursesData[index]),
trashCan: trashCan,
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('Single Tap!'),
duration: Duration(seconds: 1),
));
},
onDelete: () {
if (trashCan.contains(coursesData[index])) {
trashCan.remove(coursesData[index]);
setState(() {});
} else {
trashCan.add(coursesData[index]);
setState(() {});
}
},
);
},
),
],
),
),
);
}
}
class PrettyCard extends StatelessWidget {
final String name;
final bool isSelected;
final void Function()? onDelete;
final void Function()? onTap;
final List trashCan;
const PrettyCard(
{Key? key,
required this.name,
required this.isSelected,
this.onDelete,
this.onTap,
required this.trashCan})
: super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 2),
child: Card(
surfaceTintColor: isSelected ? Colors.black : null,
color: Colors.cyan.shade900,
child: ListTile(
dense: true,
selected: isSelected,
onTap: trashCan.isNotEmpty ? onDelete : onTap,
onLongPress: onDelete,
tileColor: Colors.cyan.shade900,
selectedColor: Colors.white,
selectedTileColor: Colors.cyan.shade900,
title: Text(name),
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.cyan.shade50,
width: 3,
style: isSelected ? BorderStyle.solid : BorderStyle.none)),
),
),
);
}
}
class Course {
final String id;
final String name;
Course({
required this.id,
required this.name,
});
}
List<Course> coursesData = [
Course(id: '1', name: 'MTH'),
Course(id: '2', name: 'STS'),
Course(id: '3', name: 'ACC'),
Course(id: '4', name: 'ETH'),
Course(id: '5', name: 'PHY'),
Course(id: '6', name: 'CSC'),
];
Refer to this repo: https://github.com/acromondx/FlutterVortex/tree/main/multi_select
Upvotes: 0
Reputation: 31406
when the user does a long press the ListTile must change the selected property to true and vice versa and the Card Color must be Changed to Something like Grey[300]
class cardy extends StatefulWidget {
@override
_cardyState createState() => new _cardyState();
}
class _cardyState extends State<cardy> {
var isSelected = false;
var mycolor=Colors.white;
@override
Widget build(BuildContext context) {
return new Card(
color: mycolor,
child: new Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
new ListTile(
selected: isSelected,
leading: const Icon(Icons.info),
title: new Text("Test"),
subtitle: new Text("Test Desc"),
trailing: new Text("3"),
onLongPress: toggleSelection // what should I put here,
)
]),
);
}
void toggleSelection() {
setState(() {
if (isSelected) {
mycolor=Colors.white;
isSelected = false;
} else {
mycolor=Colors.grey[300];
isSelected = true;
}
});
}
}
EDIT: if you want to get the Border coloring effect make the column Inside the Container and set the decoration property to a variable and call it border and Edit the select method
void toggleSelection() {
setState(() {
if (isSelected) {
border=new BoxDecoration(border: new Border.all(color: Colors.white));
mycolor = Colors.white;
isSelected = false;
} else {
border=new BoxDecoration(border: new Border.all(color: Colors.grey));
mycolor = Colors.grey[300];
isSelected = true;
}
});
}
Upvotes: 17