gzx_dropdown_menu
是一个Flutter自定义功能强大的轻量级下拉筛选菜单Package,它支持iOS和Android。
功能介绍
A custom is strong dropdown menu for Flutter. Easy to use and powerful for customization, it's up to you what you want to display in the dropdown menu!
- Custom dropdown header
- Custom dropdown header item
- Custom dropdown menu
- Custom dropdown menu animation
- Control dropdown menu show or hide
待办事项
- 由于GZXDropDownMenu只能在Stack内使用,扩展性还不够强
- 支持CustomScrollView和NestedScrollView
- ..........
Gif效果图
效果图展示了仿美团和淘宝的下拉筛选菜单。
- 美团的代码就在这个仓库的example目录下
- 淘宝的代码在Flutter 淘宝
如何使用
目前已发布到Pub,你可以在Pub官网查看最新的版本和更新说明!去Pub官网查看
1、添加gzx_dropdown_menu package
打开pubspec.yaml文件 添加如下代码
gzx_dropdown_menu: ^3.1.0
添加后打开Terminal,执行flutter packages get
2、使用
- 强烈建议你先clone下本仓库
- 然后运行下看下效果
- 打开本仓库example项目下的gzx_dropdown_menu_test_page.dart文件自己看。
没空编辑文字了,而且说这么多还不如你直接运行下看下效果,然后看下代码,就知道如何使用了。
算了🤪🤪🤪🙄还是简单说下吧!!!
你只需要将GZXDropDownHeader和GZXDropDownMenu嵌套到你的代码中即可
github地址:
GZXDropDownHeader
这里要注意了,这些参数不是必须要要写的,我写出来只是让你知道强大的自定义功能,实际上就前面三个参数是必填的
// 下拉菜单头部
GZXDropDownHeader(
// 下拉的头部项,目前每一项,只能自定义显示的文字、图标、图标大小修改
items: [
GZXDropDownHeaderItem(_dropDownHeaderItemStrings[0]),
GZXDropDownHeaderItem(
_dropDownHeaderItemStrings[1],
iconData: Icons.keyboard_arrow_down,
iconDropDownData: Icons.keyboard_arrow_up,
),
GZXDropDownHeaderItem(
_dropDownHeaderItemStrings[2],
style: TextStyle(color: Colors.green),
iconData: Icons.arrow_upward,
iconDropDownData: Icons.arrow_downward,
),
GZXDropDownHeaderItem(
_dropDownHeaderItemStrings[3],
iconData: Icons.filter_frames,
iconSize: 18,
),
],
// GZXDropDownHeader对应第一父级Stack的key
stackKey: _stackKey,
// controller用于控制menu的显示或隐藏
controller: _dropdownMenuController,
// 当点击头部项的事件,在这里可以进行页面跳转或openEndDrawer
onItemTap: (index) {
if (index == 3) {
_dropdownMenuController.hide();
_scaffoldKey.currentState!.openEndDrawer();
}
},
// 头部的高度
height: 40,
// 头部背景颜色
color: Colors.red,
// 头部边框宽度
borderWidth: 1,
// 头部边框颜色
borderColor: Color(0xFFeeede6),
// 分割线高度
dividerHeight: 20,
// 分割线颜色
dividerColor: Color(0xFFeeede6),
// 文字样式
style: TextStyle(color: Color(0xFF666666), fontSize: 14),
// 下拉时文字样式
dropDownStyle: TextStyle(
fontSize: 14,
color: Theme.of(context).primaryColor,
),
// 图标大小
iconSize: 20,
// 图标颜色
iconColor: Color(0xFFafada7),
// 下拉时图标颜色
iconDropDownColor: Theme.of(context).primaryColor,
),
GZXDropDownMenu
// 下拉菜单,注意GZXDropDownMenu目前只能在Stack内,后续有时间会改进,以及支持CustomScrollView和NestedScrollView
GZXDropDownMenu(
// controller用于控制menu的显示或隐藏
controller: _dropdownMenuController,
// 下拉菜单显示或隐藏动画时长
animationMilliseconds: 300,
// 下拉后遮罩颜色
//maskColor: Theme.of(context).primaryColor.withOpacity(0.5),
//maskColor: Colors.red.withOpacity(0.5),
dropdownMenuChanging: (isShow, index) {
setState(() {
_dropdownMenuChange = '(正在${isShow ? '显示' : '隐藏'}$index)';
print(_dropdownMenuChange);
});
},
dropdownMenuChanged: (isShow, index) {
setState(() {
_dropdownMenuChange = '(已经${isShow ? '显示' : '隐藏'}$index)';
print(_dropdownMenuChange);
});
},
// 下拉菜单,高度自定义,你想显示什么就显示什么,完全由你决定,你只需要在选择后调用_dropdownMenuController.hide();即可
menus: [
GZXDropdownMenuBuilder(
dropDownHeight: 40 * 8.0,
dropDownWidget: _buildAddressWidget((selectValue) {
_dropDownHeaderItemStrings[0] = selectValue;
_dropdownMenuController.hide();
setState(() {});
})),
GZXDropdownMenuBuilder(
dropDownHeight: 40 * 8.0,
dropDownWidget: _buildConditionListWidget(_brandSortConditions, (value) {
_selectBrandSortCondition = value;
_dropDownHeaderItemStrings[1] =
_selectBrandSortCondition.name == '全部' ? '品牌' : _selectBrandSortCondition.name;
_dropdownMenuController.hide();
setState(() {});
})),
GZXDropdownMenuBuilder(
dropDownHeight: 40.0 * _distanceSortConditions.length,
dropDownWidget: _buildConditionListWidget(_distanceSortConditions, (value) {
_selectDistanceSortCondition = value;
_dropDownHeaderItemStrings[2] = _selectDistanceSortCondition.name;
_dropdownMenuController.hide();
setState(() {});
})),
],
),
相关Repository
flutter_custom_dropdown
本组件由Github作者best-flutter插件flutter_dropdown_menu更改而来,由于更新问题,以及使用上不满足业务问题自己修改了相关bug做了更新迭代,所以重新集成为新插件
DefaultDropdownMenuController
功能:包裹页面提供默认Controller
功能参数 | 是否必要 | 类型 | 备注 |
---|---|---|---|
onSelected | true | bool | 选中时,触发controller.selected时会回调此方法 |
child | true | widget | 包裹内容 |
DropdownHeader
功能:下拉头部模块
功能参数 | 是否必要 | 类型 | 备注 |
---|---|---|---|
isSideline | false | bool | 是否需要分割线 |
onTap | false | func | 触发头部回调,内部自动提供,自定义头部事件需自定义 |
titles | true | List<String> | 头部显示title列表 |
selectIsChangingColor | false | bool | 选中是否更改回显title字段可specialModules联合使用 |
specialModules | false | List<int> | 选中是否只改变title颜色不更改title文字,此功能selectIsChangingColor必须为true,权重大于selectIsChangingColor功能 |
DropdownMenu
功能:悬停筛选模块
功能参数 | 是否必要 | 类型 | 备注 |
---|---|---|---|
menus | true | List<DropdownMenuBuilder> | list长度必须与titles长度一致 |
packUpHeight | false | double | 收起长度不够时可自行添加 |
hideDuration | false | Duration | 收起时自定义时长 |
showDuration | false | Duration | 展开时自定义时长 |
showCurve | false | Curve | 自定义动画 |
hideCurve | false | Curve | 自定义动画 |
blur | false | double | 蒙层透明值 |
onHide | false | VoidCallback | 蒙层触发操作回调 |
switchStyle | false | DropdownMenuShowHideSwitchStyle | 菜单样式 |
maxMenuHeight | false | double | 最大高度,未提供自动计算时,需要指定最大高度 |
DropdownMenuBuilder
功能:menus内容
功能参数 | 是否必要 | 类型 | 备注 |
---|---|---|---|
builder | true | WidgetBuilder | 下拉内容 |
screenHeight | false | double | 最大高度,默认屏幕高度,自动计算时必须填写 |
draughtHeight | true | double | 内容高度, |
bottomSpacingHeight | false | double | 距离屏幕底部高度,自动计算时必须填写 |
单选图片功能详解
功能 | 实现功能 | 内容 |
---|---|---|
交易类型 | 单选选中,不提供title变色,不提供title更改 | 条件:剔除元数据title字段 |
范围 | 单选选中,提供title变色,不提供title更改 | 条件:添加元数据title字段,将header下标放入specialModules,开启selectIsChangingColor |
排序 | 单选选中,提供title变色,提供title更改 | 条件:添加元数据title字段,禁止将header下标放入specialModules,开启selectIsChangingColor |
DropdownListMenu
多功能tempalte,单选+多选+自定义按钮+自定义输入
功能参数 | 是否必要 | 类型 | 备注 | |
---|---|---|---|---|
selectedIndex | false | Object | 默认选中 | |
isOperatingButton | false | bool | 是否需要按钮 | |
isCustomInput | false | bool | 是否需要自定义输入 | |
customInput | false | CustomInputClass | 定义自定义输入回显值的key与输入框HintText | |
keyWords | true | String | 数据是否重复判断依据 | |
valueKey | false | String | 当元数据没有title字段时,显示内容的key需要传入 | 也可以自定义itemBuilder内容 |
isMultiple | false | bool | 是否多选 | |
data | true | List<Object> | 元数据内容 | |
itemBuilder | true | MenuItemBuilder | 展示item布局,可自定义 |
功能实现 | 实现功能 | 内容 |
---|---|---|
交易金额 | 多选+自定义输入+自定义按钮 | 看图 |
范围 | 多选 | 看图 |
排序 | 多选+自定义按钮 | 看图 |
DropdownMenuCustomize
功能:自定义下拉内容
功能参数 | 是否必要 | 类型 | 备注 |
---|---|---|---|
data | false | List<T> | 传入内容 |
itemBuilder | true | BlankMenuItemBuilder | 内容整个布局 |
额外使用功能:
DropdownMenuController controller; 控制显示关闭,可以配合WillPopScope返回时监听是否关闭并进行关闭>之后再进行页面退出 onWillPop: () async{ if(controller == null || controller.event == DropdownEvent.HIDE){ Navigator.pop(context); } controller.hide(); return; } GlobalKey _globalKey;获取context,必须有变化的组件下,绝对布局或者滚动,需要获取绝对布局的context ScrollController scrollController;控制动画的
controller.assignment({'title': '更多---'}, menuIndex);///自定义内容时没有用到select传输数据可以由次方法重>新更改title
代码:
class MotionlessScreeningFilter extends StatefulWidget {
@override
_MotionlessScreeningFilterState createState() =>
_MotionlessScreeningFilterState();
}
class _MotionlessScreeningFilterState extends State<MotionlessScreeningFilter> {
String value1;
String value2;
String value3;
@override
Widget build(BuildContext context) {
return Container(
child: DefaultDropdownMenuController(
onSelected: ({int menuIndex, dynamic data}) {
print("int menuIndex, dynamic data = $menuIndex,$data");
if (menuIndex == 0) {
value1 = '选中下标$menuIndex,\n选中内容$data';
}
if (menuIndex == 1) {
value2 = '选中下标$menuIndex,\n选中内容$data';
}
if (menuIndex == 2) {
value3 = '选中下标$menuIndex,\n选中内容$data';
}
setState(() {});
},
child: Stack(
children: [
Column(
children: [
Container(
color: Colors.white,
child: buildDropdownHeader()
),
Expanded(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('交易类型选中 : ${value1 ?? ''}'),
const SizedBox(height: 10.0,),
Text('范围选中 : ${value2 ?? ''}'),
const SizedBox(height: 10.0,),
Text('排序选中 : ${value3 ?? ''}'),
],
),
)
),
Container(
alignment: Alignment.centerLeft,
color: const Color(0XFF00CCA9),
child: Text(
'交易类型筛选:单选,不提供选中头部回显,在元数据中剔除title字段即可 \n\n范围筛选:单选,不提供选中头部回显,但是提供选中头部颜色更改,使用specialModules属性标注,\n\n排序类型筛选:单选,提供选中内容头部回显不剔除title字段,设置selectIsChangingColor属性',
style: TextStyle(
color: Colors.white
),
),
)
],
),
Padding(
padding: const EdgeInsets.only(top: 40),
child: buildDropdownMenu(context))
],
),
)
);
}
DropdownHeader buildDropdownHeader({DropdownMenuHeadTapCallback onTap}) {
return DropdownHeader(
isSideline: false,
onTap: onTap,
titles: ['交易类型', '范围', '排序'],
selectIsChangingColor: true,
specialModules: [1],
///特殊模块,选中数据只亮起,不需要更改头部title,下标为1
);
}
DropdownMenu buildDropdownMenu(BuildContext context) {
return new DropdownMenu(
menus: [
DropdownMenuBuilder(
builder: (BuildContext context) {
return DropdownListMenu(
selectedIndex: FilterData.housingTypes[0],
isOperatingButton: false,
keyWords: "key",
data: FilterData.housingTypes,
valueKey: 'value',
itemBuilder: buildCheckItem,
);
},
screenHeight: MediaQuery
.of(context)
.size
.height,
draughtHeight: 60 * 2.5,
bottomSpacingHeight: 168.0
),
DropdownMenuBuilder(
builder: (BuildContext context) {
return DropdownListMenu(
selectedIndex: FilterData.ranges[0],
isOperatingButton: false,
keyWords: "key",
data: FilterData.ranges,
itemBuilder: buildCheckItem,
);
},
screenHeight: MediaQuery
.of(context)
.size
.height,
draughtHeight: 60 * 2.5,
bottomSpacingHeight: 168.0
),
DropdownMenuBuilder(
builder: (BuildContext context) {
return DropdownListMenu(
selectedIndex: FilterData.sort[0],
isOperatingButton: false,
keyWords: "key",
data: FilterData.sort,
itemBuilder: buildCheckItem,
);
},
screenHeight: MediaQuery
.of(context)
.size
.height,
draughtHeight: 60 * 6.66,
bottomSpacingHeight: 168.0 + 50.0
),
]
);
}
}