Flutter 实现多选底部弹窗

简介: 本篇介绍了底部弹窗实现多选的方式,其中实现的方式还可以有很多种,例如直接在自定义组件中使用有状态组件。这里介绍的方法可以作为一个参考,通过动态构建有状态组件能够简单快速地实现底部弹窗的多选功能。
Flutter 底部弹窗ModelBottomSheet详解一篇中介绍了底部弹窗的实现。发出后有在琢磨如何实现多选,这也是很常用的一个功能。本篇介绍实现多选的思路和实现方式。

屏幕录制2021-06-09 下午10.57.51.gif

多选和单选的不同之处

单选的时候,选中一个就可以直接把结果返回,因此本身底部弹窗无需状态管理。但到多选的时候,需要知道当前选中的选项,有选项被点击的时候需要存储下来,当再次被点击的时候要清空这个选项,同时界面还需要同步更新,因此就涉及到状态管理了。

实现方式

在Flutter 中提供了一个 StatefulBuilder 的类,提供了一个 builder方法构建有状态组件,并且提供了状态更新方法,因此在里面完成状态管理。

StatefulBuilder(builder: (context1, setState) {
      return Widget;
    }
)

在这个 builder 方法中,setState 其实就是对应状态组件的setState 对应的方法,这个 state 就是用于控制 StatefulBuilder 生成的组件的状态的。这种方式有点类似于 ReactuseState 的钩子函数用法。

界面变更

首先底部弹窗的头部组件要更换,需要增加确认按钮,将构建该组件的方法抽离出来如下所示:

Widget _getModalSheetHeaderWithConfirm(String title,
      {Function onCancel, Function onConfirm}) {
  return SizedBox(
    height: 50,
    child: Row(
      children: [
        IconButton(
          icon: Icon(Icons.close),
          onPressed: () {
            onCancel();
          },
        ),
        Expanded(
          child: Center(
            child: Text(
              title,
              style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0),
            ),
          ),
        ),
        IconButton(
            icon: Icon(
              Icons.check,
              color: Colors.blue,
            ),
            onPressed: () {
              onConfirm();
            }),
      ],
    ),
  );
}

通过这个方法可以通过外部参数传入标题,取消响应事件回调和确认事件回调,通用性更强。

其次是选项需要有图标标记,选中时显示为勾选框,未选中时是空白框,这需要通过状态数据来控制。这里我们使用了 Set 类型,保证选中的数据集是不重复的。在点击选项时,如果选项对应数组的下标在 Set 内,则从中移出,表示取消选择;如果不在 Set内,则加入其中,表示选中。这个过程需要包在 state 里,以更新界面。通过列表元素当前的下标是否在 Set 内,如果在则显示为选中,不在则显示未选中。

最后是确认事件的回调,确认后将 Set 的元素转换为数组返回,然后供上级业务使用选中的下标数组判断选择了那些数据。

代码实现

关键代码实现如下,重点关注一下StatefulBuilder的使用和利用 Set 这一数据类型对应的选择和取消选择的操作业务逻辑。

Future<List<int>> _showMultiChoiceModalBottomSheet(
      BuildContext context, List<String> options) async {
  Set<int> selected = Set<int>();
  return showModalBottomSheet<List<int>>(
    backgroundColor: Colors.transparent,
    isScrollControlled: true,
    context: context,
    builder: (BuildContext context) {
      return StatefulBuilder(builder: (context1, setState) {
        return Container(
          clipBehavior: Clip.antiAlias,
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.only(
              topLeft: const Radius.circular(20.0),
              topRight: const Radius.circular(20.0),
            ),
          ),
          height: MediaQuery.of(context).size.height / 2.0,
          child: Column(children: [
            _getModalSheetHeaderWithConfirm('多选底部弹窗', 
                onCancel: () {
                  Navigator.of(context).pop();
                }, 
                onConfirm: () {
                  Navigator.of(context).pop(selected.toList());
                },
            ),
            Divider(height: 1.0),
            Expanded(
              child: ListView.builder(
                itemBuilder: (BuildContext context, int index) {
                  return ListTile(
                    trailing: Icon(
                        selected.contains(index)
                            ? Icons.check_box
                            : Icons.check_box_outline_blank,
                        color: Theme.of(context).primaryColor),
                    title: Text(options[index]),
                    onTap: () {
                      setState(() {
                        if (selected.contains(index)) {
                          selected.remove(index);
                        } else {
                          selected.add(index);
                        }
                      });
                    },
                  );
                },
                itemCount: options.length,
              ),
            ),
          ]),
        );
      });
    },
  );
}

总结

本篇介绍了底部弹窗实现多选的方式,其中实现的方式还可以有很多种,例如直接在自定义组件中使用有状态组件。这里介绍的方法可以作为一个参考,通过动态构建有状态组件能够简单快速地实现底部弹窗的多选功能。


欢迎关注个人公众号:岛上码农

相关文章
|
JSON Dart IDE
Flutter实现国际化
开发一个App,如果我们的App需要面向不同的语种(比如中文、英文、繁体等),那么我们需要对齐进行国际化开发
889 0
Flutter实现国际化
Flutter 底部导航栏BottomNavigationBar,并关联PageView实现滑动切换
Flutter 底部导航栏BottomNavigationBar,并关联PageView实现滑动切换
308 0
|
Dart IDE 开发工具
Flutter 图文并茂列表实现
Flutter使用 ListView 完成列表的构建,界面实现的关键工作实际是布局子元素的拆分。剩下的实现方式存在多种,看各人喜好。但是,需要注意避免过多嵌套导致代码不好维护,并需要提高复用性。
808 2
Flutter 图文并茂列表实现
|
数据安全/隐私保护 UED
Flutter 使用自定义fluro 路由实现访问权限控制
本篇介绍了利用 Fluro 路由管理实现路由权限拦截的两种方式,两种方式各有好处,使用过程中可以根据实际情况决定使用哪一种方法。
523 1
Flutter 使用自定义fluro 路由实现访问权限控制
|
存储 数据安全/隐私保护
Flutter App页面路由及路由拦截实现
直接使用页面跳转会带来诸多缺陷,通过路由管理可以降低页面耦合,提高代码的可维护性和权限控制。本篇介绍了 Flutter 的路由管理和拦截实现。
1139 1
Flutter App页面路由及路由拦截实现
|
容器
Flutter 底部弹窗ModelBottomSheet详解
本篇介绍了三种 ModalBottomSheet 的方式,实际开发过程中,还可以根据需要,利用 ModalBottomSheet的 builder 方法构建自定义的底部弹窗,满足业务需要。
1061 0
Flutter 底部弹窗ModelBottomSheet详解
|
前端开发 API Android开发
Flutter实现动画
对于一个前端的App来说,添加适当的动画,可以给用户更好的体验和视觉效果。所以无论是原生的iOS或Android,还是前端开发中都会提供完成某些动画的API。 Flutter有自己的渲染闭环,我们当然可以给它提供一定的数据模型,来让它帮助我们实现对应的动画效果。
175 0
Flutter实现动画
Flutter:实现红包晃动效果
很多app打开会有红包悬浮在某个角落,然后为了吸引注意力,会将红包晃动起来,这个效果非常简单
275 0
|
前端开发
在Flutter里实现一个开心农场地块布局!Web前端工程师也可以看看,作为Flutter入门。
为避免贴大段代码,文中代码部分仅作为参考,并非全部代码,请理解后自行补全或者下载源码进行学习。
230 0
在Flutter里实现一个开心农场地块布局!Web前端工程师也可以看看,作为Flutter入门。
|
编解码 Dart Java
【Flutter】Flutter 混合开发 ( Flutter 与 Native 通信 | Android 端实现 MethodChannel 通信 )
【Flutter】Flutter 混合开发 ( Flutter 与 Native 通信 | Android 端实现 MethodChannel 通信 )
284 0