FilterList is a flutter package which provide utility to search/filter on the basis of single/multiple selection from provided dynamic list.
dependencies:
filter_list: ^<latest_version>
import package:filter_list/filter_list.dart';
class User {
final String? name;
final String? avatar;
User({this.name, this.avatar});
}
List<User> userList = [
User(name: "Jon", avatar: ""),
User(name: "Lindsey ", avatar: ""),
User(name: "Valarie ", avatar: ""),
User(name: "Elyse ", avatar: ""),
User(name: "Ethel ", avatar: ""),
User(name: "Emelyan ", avatar: ""),
User(name: "Catherine ", avatar: ""),
User(name: "Stepanida ", avatar: ""),
User(name: "Carolina ", avatar: ""),
User(name: "Nail ", avatar: ""),
User(name: "Kamil ", avatar: ""),
User(name: "Mariana ", avatar: ""),
User(name: "Katerina ", avatar: ""),
];
Below is a example of using filter list widgets with minimal code however there is a lot more inside the widget for you to fully customize the widget.
FilterListDialog.display
void openFilterDialog() async {
await FilterListDialog.display<User>(
context,
listData: userList,
selectedListData: selectedUserList,
choiceChipLabel: (user) => user!.name,
validateSelectedItem: (list, val) => list!.contains(val),
onItemSearch: (user, query) {
return user.name!.toLowerCase().contains(query.toLowerCase());
},
onApplyButtonClick: (list) {
setState(() {
selectedUserList = List.from(list!);
});
Navigator.pop(context);
},
);
}
If
Apply
button is pressed without making any selection it will return empty list of items.
openFilterDialog
function on button tap to display filter dialog@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: openFilterDialog,
child: Icon(Icons.add),
),
body: selectedUserList == null || selectedUserList!.length == 0
? Center(child: Text('No user selected'))
: ListView.builder(
itemBuilder: (context, index) {
return ListTile(
title: Text(selectedUserList![index].name!),
);
},
itemCount: selectedUserList!.length,
),
);
}
FilterListWidget
.
class FilterPage extends StatelessWidget {
const FilterPage({Key? key, this.selectedUserList})
: super(key: key);
final List<User>? selectedUserList;
@override
Widget build(BuildContext context) {
return Scaffold(
body: FilterListWidget<User>(
listData: userList,
selectedListData: selectedUserList,
onApplyButtonClick: (list) {
// do something with list ..
},
choiceChipLabel: (item) {
/// Used to display text on chip
return item!.name;
},
validateSelectedItem: (list, val) {
/// identify if item is selected or not
return list!.contains(val);
},
onItemSearch: (user, query) {
/// When search query change in search bar then this method will be called
///
/// Check if items contains query
return user.name!.toLowerCase().contains(query.toLowerCase());
},
),
);
}
}
FilterListDelegate
. Create a function and call FilterListDelegate.open()
on button tap.
void openFilterDelegate() async {
await FilterListDelegate.open<User>(
context: context,
list: userList,
onItemSearch: (user, query) {
return user.name!.toLowerCase().contains(query.toLowerCase());
},
tileLabel: (user) => user!.name,
emptySearchChild: Center(child: Text('No user found')),
searchFieldHint: 'Search Here..',
onApplyButtonClick: (list) {
// Do something with selected list
},
);
}
Empty screen | FilterListDialog | Selected chip | Result from dialog |
---|---|---|---|
Default | Customized | customized |
---|---|---|
Single selection | Multiple selection | Multiple selection |
---|---|---|
Search through list | Customized Tile |
---|---|
Parameter | Type | Description |
---|---|---|
height | double | Set height of filter dialog. |
width | double | Set width of filter dialog. |
hideCloseIcon | bool | Hide close Icon. |
hideHeader | bool | Hide complete header section from filter dialog. |
headerCloseIcon | Widget | Widget to close the dialog. |
hideSelectedTextCount | bool | Hide selected text count. |
hideSearchField | bool | Hide search text field. |
headlineText | String | Set header text of filter dialog. |
backgroundColor | Color | Set background color of filter color |
listData | List<T>() | Populate filter dialog with text list. |
selectedListData | List<T>() | Marked selected text in filter dialog. |
choiceChipLabel | String Function(T item) | Display text on choice chip. |
validateSelectedItem | bool Function(List<T>? list, T item) | Identifies weather a item is selected or not |
onItemSearch | List<T> Function(List<T>? list, String text) | Perform search operation and returns filtered list |
choiceChipBuilder | Widget Function(BuildContext context, T? item, bool? isSelected) | The choiceChipBuilder is a builder to design custom choice chip. |
onApplyButtonClick | Function(List<T> list) | Returns list of items when apply button is clicked |
validateRemoveItem | List<T> Function(List<T>? list, T item) | Function Delegate responsible for delete item from list |
resetButtonText | String | Reset button text to customize or translate |
allButtonText | String | All button text to customize or translate |
selectedItemsText | String | Selected items text to customize or translate |
controlButtons | List<ControlButtonType> | configure which control button needs to be display on bottom of dialog along with 'Apply' button. |
insetPadding | EdgeInsets | The amount of padding added to the outside of the dialog. |
themeData | FilterListThemeData | Configure theme of filter dialog and widget. |
choiceChipTheme | ChoiceChipThemeData | Configure theme of choice chip. |
controlButtonBarTheme | ControlButtonBarThemeData | Configure theme of control button bar |
controlButtonTheme | ControlButtonThemeData | Configure theme of control button. |
headerTheme | HeaderThemeData | Configure theme of filter header. |
T
can be a String or any user defined Model
Name | Stars | Pub |
---|---|---|
Empty widget | ||
Add Thumbnail | ||
Country Provider |
I welcome and encourage all pull requests. It usually will take me within 24-48 hours to respond to any issue or request.
Sonu Sharma (Twitter) (Youtube) (Insta)
Run this command:
With Flutter:
$ flutter pub add filter_list
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
filter_list: ^1.0.2
Alternatively, your editor might support flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:filter_list/filter_list.dart';
import 'package:filter_list/filter_list.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
debugShowCheckedModeBanner: false,
home: const MyHomePage(title: 'Filter list example'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, this.title}) : super(key: key);
final String? title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<User>? selectedUserList = [];
Future<void> openFilterDelegate() async {
await FilterListDelegate.show<User>(
context: context,
list: userList,
selectedListData: selectedUserList,
theme: FilterListDelegateThemeData(
listTileTheme: ListTileThemeData(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
tileColor: Colors.white,
selectedColor: Colors.red,
selectedTileColor: const Color(0xFF649BEC).withOpacity(.5),
textColor: Colors.blue,
),
),
// enableOnlySingleSelection: true,
onItemSearch: (user, query) {
return user.name!.toLowerCase().contains(query.toLowerCase());
},
tileLabel: (user) => user!.name,
emptySearchChild: const Center(child: Text('No user found')),
// enableOnlySingleSelection: true,
searchFieldHint: 'Search Here..',
/*suggestionBuilder: (context, user, isSelected) {
return ListTile(
title: Text(user.name!),
leading: const CircleAvatar(
backgroundColor: Colors.blue,
),
selected: isSelected,
);
},*/
onApplyButtonClick: (list) {
setState(() {
selectedUserList = list;
});
},
);
}
Future<void> _openFilterDialog() async {
await FilterListDialog.display<User>(
context,
hideSelectedTextCount: true,
themeData: FilterListThemeData(context),
headlineText: 'Select Users',
height: 500,
listData: userList,
selectedListData: selectedUserList,
choiceChipLabel: (item) => item!.name,
validateSelectedItem: (list, val) => list!.contains(val),
controlButtons: [ControlButtonType.All, ControlButtonType.Reset],
onItemSearch: (user, query) {
/// When search query change in search bar then this method will be called
///
/// Check if items contains query
return user.name!.toLowerCase().contains(query.toLowerCase());
},
onApplyButtonClick: (list) {
setState(() {
selectedUserList = List.from(list!);
});
Navigator.pop(context);
},
/// uncomment below code to create custom choice chip
/* choiceChipBuilder: (context, item, isSelected) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
decoration: BoxDecoration(
border: Border.all(
color: isSelected! ? Colors.blue[300]! : Colors.grey[300]!,
)),
child: Text(
item.name,
style: TextStyle(
color: isSelected ? Colors.blue[300] : Colors.grey[500]),
),
);
}, */
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title!),
),
bottomNavigationBar: Padding(
padding: const EdgeInsets.only(bottom: 30),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
TextButton(
onPressed: () async {
final list = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FilterPage(
allTextList: userList,
selectedUserList: selectedUserList,
),
),
);
if (list != null) {
setState(() {
selectedUserList = List.from(list);
});
}
},
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.blue),
),
child: const Text(
"Filter Page",
style: TextStyle(color: Colors.white),
),
),
TextButton(
onPressed: _openFilterDialog,
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.blue),
),
child: const Text(
"Filter Dialog",
style: TextStyle(color: Colors.white),
),
// color: Colors.blue,
),
TextButton(
onPressed: openFilterDelegate,
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.blue),
),
child: const Text(
"Filter Delegate",
style: TextStyle(color: Colors.white),
),
// color: Colors.blue,
),
],
),
),
body: Column(
children: <Widget>[
if (selectedUserList == null || selectedUserList!.isEmpty)
const Expanded(
child: Center(
child: Text('No user selected'),
),
)
else
Expanded(
child: ListView.separated(
itemBuilder: (context, index) {
return ListTile(
title: Text(selectedUserList![index].name!),
);
},
separatorBuilder: (context, index) => const Divider(),
itemCount: selectedUserList!.length,
),
),
],
),
);
}
}
class FilterPage extends StatelessWidget {
const FilterPage({Key? key, this.allTextList, this.selectedUserList})
: super(key: key);
final List<User>? allTextList;
final List<User>? selectedUserList;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Filter list Page"),
),
body: SafeArea(
child: FilterListWidget<User>(
themeData: FilterListThemeData(context),
hideSelectedTextCount: true,
listData: userList,
selectedListData: selectedUserList,
onApplyButtonClick: (list) {
Navigator.pop(context, list);
},
choiceChipLabel: (item) {
/// Used to print text on chip
return item!.name;
},
// choiceChipBuilder: (context, item, isSelected) {
// return Container(
// padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
// margin: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
// decoration: BoxDecoration(
// border: Border.all(
// color: isSelected! ? Colors.blue[300]! : Colors.grey[300]!,
// )),
// child: Text(item.name),
// );
// },
validateSelectedItem: (list, val) {
/// identify if item is selected or not
return list!.contains(val);
},
onItemSearch: (user, query) {
/// When search query change in search bar then this method will be called
///
/// Check if items contains query
return user.name!.toLowerCase().contains(query.toLowerCase());
},
),
),
);
}
}
class User {
final String? name;
final String? avatar;
User({this.name, this.avatar});
}
/// Creating a global list for example purpose.
/// Generally it should be within data class or where ever you want
List<User> userList = [
User(name: "Abigail", avatar: "user.png"),
User(name: "Audrey", avatar: "user.png"),
User(name: "Ava", avatar: "user.png"),
User(name: "Bella", avatar: "user.png"),
User(name: "Bernadette", avatar: "user.png"),
User(name: "Carol", avatar: "user.png"),
User(name: "Claire", avatar: "user.png"),
User(name: "Deirdre", avatar: "user.png"),
User(name: "Donna", avatar: "user.png"),
User(name: "Dorothy", avatar: "user.png"),
User(name: "Faith", avatar: "user.png"),
User(name: "Gabrielle", avatar: "user.png"),
User(name: "Grace", avatar: "user.png"),
User(name: "Hannah", avatar: "user.png"),
User(name: "Heather", avatar: "user.png"),
User(name: "Irene", avatar: "user.png"),
User(name: "Jan", avatar: "user.png"),
User(name: "Jane", avatar: "user.png"),
User(name: "Julia", avatar: "user.png"),
User(name: "Kylie", avatar: "user.png"),
User(name: "Lauren", avatar: "user.png"),
User(name: "Leah", avatar: "user.png"),
User(name: "Lisa", avatar: "user.png"),
User(name: "Melanie", avatar: "user.png"),
User(name: "Natalie", avatar: "user.png"),
User(name: "Olivia", avatar: "user.png"),
User(name: "Penelope", avatar: "user.png"),
User(name: "Rachel", avatar: "user.png"),
User(name: "Ruth", avatar: "user.png"),
User(name: "Sally", avatar: "user.png"),
User(name: "Samantha", avatar: "user.png"),
User(name: "Sarah", avatar: "user.png"),
User(name: "Theresa", avatar: "user.png"),
User(name: "Una", avatar: "user.png"),
User(name: "Vanessa", avatar: "user.png"),
User(name: "Victoria", avatar: "user.png"),
User(name: "Wanda", avatar: "user.png"),
User(name: "Wendy", avatar: "user.png"),
User(name: "Yvonne", avatar: "user.png"),
User(name: "Zoe", avatar: "user.png"),
];
/// Another example of [FilterListWidget] to filter list of strings
/*
FilterListWidget<String>(
listData: [
"One",
"Two",
"Three",
"Four",
"five",
"Six",
"Seven",
"Eight",
"Nine",
"Ten"
],
selectedListData: ["One", "Three", "Four", "Eight", "Nine"],
onApplyButtonClick: (list) {
Navigator.pop(context, list);
},
choiceChipLabel: (item) {
/// Used to print text on chip
return item;
},
validateSelectedItem: (list, val) {
/// identify if item is selected or not
return list!.contains(val);
},
onItemSearch: (text, query) {
return text.toLowerCase().contains(query.toLowerCase());
},
)
*/
Download details:
Author: TheAlphamerc
Source: https://github.com/TheAlphamerc/flutter_plugin_filter_list