list_selection_widget
List Selection Widget is a Flutter package that provides a highly customizable dropdown list to select single or multiple options with ease.
Preview
Usage
First, import the package:
import 'package:list_selection_widget/list_selection_widget.dart';
The package provides two main constructors: ListSelectionWidget.single for single selection and ListSelectionWidget.multi for multiple selections.
The generic
ListSelectionWidget(...)constructor is deprecated because it can combine single-selection and multi-selection parameters in invalid ways. UseListSelectionWidget.single(...)orListSelectionWidget.multi(...)for new code.
Single Selection
ListSelectionWidget<String>.single(
hintText: 'Select an option',
listItems: [
SelectionItem(value: 'flutter', label: 'Flutter'),
SelectionItem(value: 'react_native', label: 'React Native'),
SelectionItem(value: 'swift', label: 'Swift'),
],
selectedValue: null,
onSingleItemSelected: (item) {
print('Selected: ${item.label}');
},
autoCollapsed: true,
animationDuration: const Duration(milliseconds: 120),
)
Multiple Selection
ListSelectionWidget<String>.multi(
hintText: 'Select multiple options',
listItems: [
SelectionItem(value: 'flutter', label: 'Flutter'),
SelectionItem(value: 'react_native', label: 'React Native'),
SelectionItem(value: 'swift', label: 'Swift'),
],
multiSelectValues: [],
onMultiItemsSelected: (items) {
print('Selected: ${items.map((item) => item.label).join(', ')}');
},
)
Customization
The widget offers various customization options:
decoration: Customize the overall appearance of the widgeticonStyle: Customize the icons used in the widgettextStyle: Customize the text stylespaddingData: Adjust padding for different parts of the widgethideLines: Hide separator lines between itemsmaxHeight: Set a maximum height for the dropdown listautoCollapsed: Collapse the list automatically after an item is selectedanimationDuration: Customize the list expansion and title icon rotation durationinitiallyExpanded: Show the list opened on first buildonExpansionChanged: Listen when the list opens or closesselectedTitleBuilder: Customize the title text shown when items are selecteditemBuilder: Customize each item row while keeping the built-in selection behaviorallowDefaultRotation: Disable the built-in title icon rotation when using a custom animated icon
Migration note: use IconStyleData.trailingIcon for the title icon. The old
misspelled tailingIcon parameter was removed.
Customization Precedence
selectedTitleBuilderreplaces the default selected title text. When it is provided, the widget does not usehintTextor the comma-separated selected labels for the title.itemBuilderreplaces the default item row content. When it is provided,iconStyle.selectionCustomIcon,iconStyle.selectedIconColor,iconStyle.unselectedIconColor,iconStyle.backgroundSelectedIconColor,textStyle.itemTextStyle, andtextStyle.selectedItemTextStyleno longer affect the item row content.itemBuilderdoes not replace the row wrapper. The package still handles item taps,paddingData.itemPadding,paddingData.itemMargin, andhideLines.decoration,paddingData.contentPadding,paddingData.titlePadding,maxHeight,animationDuration, and title icon options still apply whenitemBuilderis used.
Custom Title Icon Rotation
By default, the title icon rotates when the list expands or collapses. Set
allowDefaultRotation to false when you want to keep your custom
trailingIcon static and prevent the package from rotating it.
ListSelectionWidget<String>.single(
hintText: 'Select an option',
listItems: [
SelectionItem(value: 'flutter', label: 'Flutter'),
SelectionItem(value: 'react_native', label: 'React Native'),
],
selectedValue: null,
onSingleItemSelected: (item) {
print('Selected: ${item.label}');
},
iconStyle: IconStyleData(
trailingIcon: const Icon(Icons.more_horiz),
allowDefaultRotation: false,
),
)
Example with customization:
ListSelectionWidget<String>.single(
hintText: 'Select an option',
listItems: [
SelectionItem(value: 'flutter', label: 'Flutter'),
SelectionItem(value: 'react_native', label: 'React Native'),
SelectionItem(value: 'swift', label: 'Swift'),
],
selectedValue: null,
onSingleItemSelected: (item) {
print('Selected: ${item.label}');
},
hideLines: true,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(10),
),
iconStyle: IconStyleData(
collapsedIconColor: Colors.white,
expandedIconColor: Colors.amber,
),
textStyle: TextStyleData(
titleStyle: TextStyle(color: Colors.white),
itemTextStyle: TextStyle(color: Colors.white),
),
maxHeight: 200,
autoCollapsed: true,
animationDuration: const Duration(milliseconds: 120),
)
Custom Selected Title
ListSelectionWidget<String>.multi(
hintText: 'Select options',
listItems: items,
multiSelectValues: selectedItems,
onMultiItemsSelected: (items) {
setState(() {
selectedItems = items;
});
},
selectedTitleBuilder: (items) {
if (items.isEmpty) return 'Select options';
return '${items.length} selected';
},
)
Custom Item Row
ListSelectionWidget<String>.single(
hintText: 'Select an option',
listItems: items,
selectedValue: selectedItem,
onSingleItemSelected: (item) {
setState(() {
selectedItem = item;
});
},
itemBuilder: (context, item, isSelected) {
return Row(
children: [
Icon(
isSelected ? Icons.check_circle : Icons.circle_outlined,
size: 18,
),
const SizedBox(width: 8),
Expanded(child: Text(item.label)),
],
);
},
)
Expansion State
ListSelectionWidget<String>.multi(
hintText: 'Select options',
listItems: items,
multiSelectValues: selectedItems,
onMultiItemsSelected: (items) {
setState(() {
selectedItems = items;
});
},
initiallyExpanded: true,
onExpansionChanged: (isExpanded) {
print('Expanded: $isExpanded');
},
)
Full Example
Here's a complete example demonstrating both single and multiple selection widgets:
import 'package:flutter/material.dart';
import 'package:list_selection_widget/list_selection_widget.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'List Selection Widget Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const Demo(title: 'List Selection Widget Demo'),
);
}
}
class Demo extends StatefulWidget {
const Demo({super.key, required this.title});
final String title;
@override
State<Demo> createState() => _DemoState();
}
class _DemoState extends State<Demo> {
final List<SelectionItem<String>> _listItems = [
SelectionItem(value: 'flutter', label: 'Flutter'),
SelectionItem(value: 'react_native', label: 'React Native'),
SelectionItem(value: 'swift', label: 'Swift'),
SelectionItem(value: 'kotlin', label: 'Kotlin'),
];
SelectionItem<String>? _selectedItem;
List<SelectionItem<String>> _multiSelectedItems = [];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
ListSelectionWidget<String>.single(
hintText: 'Select an item',
listItems: _listItems,
selectedValue: _selectedItem,
onSingleItemSelected: (item) {
setState(() {
_selectedItem = item;
});
},
hideLines: true,
),
const SizedBox(height: 30),
ListSelectionWidget<String>.multi(
hintText: 'Select multiple items',
listItems: _listItems,
multiSelectValues: _multiSelectedItems,
onMultiItemsSelected: (items) {
setState(() {
_multiSelectedItems = items;
});
},
),
],
),
),
);
}
}
This example demonstrates how to use both single and multiple selection widgets in a Flutter app, along with state management to track selected items.
Contributing
Contributions to improve the package are welcome. If you find any issues, please report them so they can be addressed as soon as possible.