阅读 80

Flutter 底部弹窗ModelBottomSheet的使用示例

Flutter 底部弹窗ModelBottomSheet的使用示例

 

在实际开发过程中,经常会用到底部弹窗来进行快捷操作,例如选择一个选项,选择下一步操作等等。在 Flutter 中提供了一个 showModelBottomSheet 方法用于弹出底部弹窗,本篇介绍如何使用底部弹窗。

实现效果

最终实现效果如图片所示,分布演示了基础的,全屏的和自定义的底部弹窗形式。

image.png

代码结构

在消息页面 message.dart 中,使用 Column 组件构建了三个按钮,点击每个按钮调用不同的底部弹窗显示。这部分代码不展示,核心注意的方式是按钮的 onPressed 响应方法,需要使用 async 修饰,这是因为 ModalBottomSheet 的返回结果是一个 Future 对象,需要通过 await 来获取返回结果。

onPressed: () async {   int selectedIndex = await _showCustomModalBottomSheet(context, _options);   print("自定义底部弹层:选中了第$selectedIndex个选项"); }, //... 复制代码

基本使用

基本使用对于全屏和默认只差一个参数,演示代码中,我们使用了一组模拟的数据构建选项数据,然后再传给显示底部弹窗的方法,实际这组数据大部分是从后台获取的。当 isScrollControlled 是 true 时,则是全屏弹窗,默认是 false。

Future<int> _showBasicModalBottomSheet(context, List<String> options) async {     return showModalBottomSheet<int>(       isScrollControlled: false,       context: context,       builder: (BuildContext context) {         return ListView.builder(           itemBuilder: (BuildContext context, int index) {             return ListTile(                 title: Text(options[index]),                 onTap: () {                   Navigator.of(context).pop(index);                 });           },           itemCount: options.length,         );       },     );   } 复制代码

需要注意的有四点:

  • 弹窗需要上下文的 context,这是因为实际页面展示是通过 Navigator 的 push 方法导航的新的页面完成的。

  • 弹窗的组件构建的 builder 方法,这里可以返回自己自定义的组件,后面的自定义组件就是在这里做文章。

  • 在列表的元素的选中点击事件 onTap 方法中,需要使用 Navigator的 pop 方法返回上一个页面,这里可以携带选中的下标(或其他值)返回,上一个页面可以使用 await 的方式接收对应返回的结果。

  • 点击蒙层也可以消失,这时候实际调用的方法是 Navigator.of(context).pop()。因为没有携带参数,所以接收的结果是 null,需要特殊处理一下。

自定义底部弹窗

在自定义底部弹窗中,我们做了如下自定义项:

  • 弹窗的高度指定为屏幕高度的一半,这可以通过自定义组件的 Container 高度实现。

  • 增加了标题栏,且标题栏有关闭按钮:标题在整个标题栏是居中的,而关闭按钮是在标题栏右侧顶部。这可以通过 Stack 堆栈布局组件实现不同的组件层叠及位置。

  • 左上角和右上角做了圆角处理,这个可以通过 Container 的装饰完成,但需要注意的是,由于底部弹窗默认是有颜色的,因此要显示出圆角需要将底部弹窗的颜色设置为透明。

自定义弹窗的代码如下所示:

Future<int> _showCustomModalBottomSheet(context, List<String> options) async {   return showModalBottomSheet<int>(     backgroundColor: Colors.transparent,     isScrollControlled: true,     context: context,     builder: (BuildContext context) {       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: [           SizedBox(             height: 50,             child: Stack(               textDirection: TextDirection.rtl,               children: [                 Center(                   child: Text(                     '底部弹窗',                     style: TextStyle(                         fontWeight: FontWeight.bold, fontSize: 16.0),                   ),                 ),                 IconButton(                     icon: Icon(Icons.close),                     onPressed: () {                       Navigator.of(context).pop();                     }),               ],             ),           ),           Divider(height: 1.0),           Expanded(             child: ListView.builder(               itemBuilder: (BuildContext context, int index) {                 return ListTile(                     title: Text(options[index]),                     onTap: () {                       Navigator.of(context).pop(index);                     });               },               itemCount: options.length,             ),           ),         ]),       );     },   ); } 复制代码

这里有几个额外需要注意的点:

  • 获取屏幕的尺寸可以使用MediaQuery.of(context).size属性完成。

  • Stack 组件根据子元素的次序依次堆叠,最后面的在最顶层。textDirection 用于排布起始位置。

  • 由于 Column 下面嵌套了一个 ListView,因此需要使用 Expanded 将 ListView 包裹起来,以便有足够的空间供 ListView 的内容区滚动,否则会报布局溢出警告。

总结

本篇介绍了三种 ModalBottomSheet 的方式, 可以看到 ModalBottomSheet 非常灵活。实际开发过程中,还可以根据需要,利用 ModalBottomSheet的 builder 方法返回不同的组件进而定制自己的底部弹层组件,能够满足绝大多数场景。同时,借 ModalBottomSheet 的启发,我们自己也可以使用 Navigator方法来实现其他形式的弹层,例如从底部弹出登录页,登录后再返回原页面。


作者:码出世界的淡水鱼
链接:https://juejin.cn/post/7168620905663299615


文章分类
ANDROID
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐