Flutter强大的下拉筛选菜单gzx_dropdown_menu

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地址:

gzx_dropdown_menu

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

功能参数是否必要类型备注
onSelectedtruebool选中时,触发controller.selected时会回调此方法
childtruewidget包裹内容

DropdownHeader

功能:下拉头部模块

功能参数是否必要类型备注
isSidelinefalsebool是否需要分割线
onTapfalsefunc触发头部回调,内部自动提供,自定义头部事件需自定义
titlestrueList<String>头部显示title列表
selectIsChangingColorfalsebool选中是否更改回显title字段可specialModules联合使用
specialModulesfalseList<int>选中是否只改变title颜色不更改title文字,此功能selectIsChangingColor必须为true,权重大于selectIsChangingColor功能

DropdownMenu

功能:悬停筛选模块

功能参数是否必要类型备注
menustrueList<DropdownMenuBuilder>list长度必须与titles长度一致
packUpHeightfalsedouble收起长度不够时可自行添加
hideDurationfalseDuration收起时自定义时长
showDurationfalseDuration展开时自定义时长
showCurvefalseCurve自定义动画
hideCurvefalseCurve自定义动画
blurfalsedouble蒙层透明值
onHidefalseVoidCallback蒙层触发操作回调
switchStylefalseDropdownMenuShowHideSwitchStyle菜单样式
maxMenuHeightfalsedouble最大高度,未提供自动计算时,需要指定最大高度

DropdownMenuBuilder

功能:menus内容

功能参数是否必要类型备注
buildertrueWidgetBuilder下拉内容
screenHeightfalsedouble最大高度,默认屏幕高度,自动计算时必须填写
draughtHeighttruedouble内容高度,
bottomSpacingHeightfalsedouble距离屏幕底部高度,自动计算时必须填写

单选图片功能详解

功能实现功能内容
交易类型单选选中,不提供title变色,不提供title更改条件:剔除元数据title字段
范围单选选中,提供title变色,不提供title更改条件:添加元数据title字段,将header下标放入specialModules,开启selectIsChangingColor
排序单选选中,提供title变色,提供title更改条件:添加元数据title字段,禁止将header下标放入specialModules,开启selectIsChangingColor

DropdownListMenu

多功能tempalte,单选+多选+自定义按钮+自定义输入

功能参数是否必要类型备注
selectedIndexfalseObject默认选中
isOperatingButtonfalsebool是否需要按钮
isCustomInputfalsebool是否需要自定义输入
customInputfalseCustomInputClass定义自定义输入回显值的key与输入框HintText
keyWordstrueString数据是否重复判断依据
valueKeyfalseString当元数据没有title字段时,显示内容的key需要传入也可以自定义itemBuilder内容
isMultiplefalsebool是否多选
datatrueList<Object>元数据内容
itemBuildertrueMenuItemBuilder展示item布局,可自定义
功能实现实现功能内容
交易金额多选+自定义输入+自定义按钮看图
范围多选看图
排序多选+自定义按钮看图

DropdownMenuCustomize

功能:自定义下拉内容

功能参数是否必要类型备注
datafalseList<T>传入内容
itemBuildertrueBlankMenuItemBuilder内容整个布局

额外使用功能:

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
          ),
        ]
    );
  }
}

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!对于封装一个flutter_screenutil,您可以按照以下步骤进行操作: 1. 首先,在项目的`pubspec.yaml`文件中添加`flutter_screenutil`依赖项。可以在`dependencies`部分添加以下代码: ```yaml dependencies: flutter_screenutil: ^5.0.0 ``` 2. 在您的项目中创建一个名为`screen_util.dart`的文件,用于封装`flutter_screenutil`。 3. 在`screen_util.dart`文件中导入必要的库: ```dart import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter/material.dart'; ``` 4. 创建一个名为`ScreenUtil`的类,并添加以下静态方法: ```dart class ScreenUtil { static void init(BuildContext context) { FlutterScreenUtil.init(context); } static double setWidth(double width) { return FlutterScreenUtil().setWidth(width); } static double setHeight(double height) { return FlutterScreenUtil().setHeight(height); } static double setSp(double fontSize) { return FlutterScreenUtil().setSp(fontSize); } } ``` 5. 在您的项目中的`main.dart`文件中,使用`ScreenUtil.init(context)`初始化`ScreenUtil`,例如: ```dart void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { ScreenUtil.init(context); return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(), ); } } ``` 6. 现在,您可以在项目的任何地方使用`ScreenUtil.setWidth`、`ScreenUtil.setHeight`和`ScreenUtil.setSp`来设置宽度、高度和字体大小,例如: ```dart Container( width: ScreenUtil.setWidth(200), height: ScreenUtil.setHeight(100), child: Text( 'Hello', style: TextStyle(fontSize: ScreenUtil.setSp(20)), ), ), ``` 通过以上步骤,您可以封装一个简单的`flutter_screenutil`工具类,方便在项目中使用屏幕适配功能。希望对您有所帮助!如果您还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值