热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【Flutter学习】基本组件之弹窗和提示(SnackBar、BottomSheet、Dialog)

一,概述Flutter中的操作提示主要有这么几种 SnackBar、BottomSheet、Dialog,因为 Dialog样式比较多,放最后讲好了二,介绍SnackBarSnac

一,概述  

  Flutter中的操作提示主要有这么几种 SnackBarBottomSheetDialog,因为 Dialog样式比较多,放最后讲好了

二,介绍

  • SnackBar

    SnackBar的源码相对简单

    • 构造函数
      const SnackBar({
          Key key,
          @required this.content, // 提示信息
          this.backgroundColor, // 背景色
          this.action, // SnackBar 尾部的按钮,用于一些回退操作等
          this.duration = _kSnackBarDisplayDuration, // 停留的时长,默认 4000ms
          this.animation, // 进出动画
        })
    • 示例demo
        假如我们需要实现一个功能,修改某个值,修改后给用户一个提示,同时给用户一个撤销该操作的按钮,那么就可以通过 SnackBar来简单实现。
      还有就是 SnackBar可以和 floatingActionButton完美的配合,弹出的时候不会遮挡住 fab
      class _PromptDemoPageState extends State {
        var count = 0;
      
        @override
        void initState() {
          super.initState();
        }
      
        @override
        void dispose() {
          super.dispose();
        }
      
        // 自增操作
        increase() {
          setState(() => count++);
        }
      
        // 自减操作
        decrease() {
          setState(() => count--);
        }
      
        _changeValue(BuildContext context) {
          increase();
          Scaffold.of(context).showSnackBar(SnackBar(
              content: Text('当前值已修改'),
              action: SnackBarAction(label: '撤销', onPressed: decrease),
              duration: Duration(milliseconds: 2000)));
        }
      
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            appBar: AppBar(
              title: Text('Prompt Demo'),
            ),
            body: Column(children: [
              Text('当前值:$count', style: TextStyle(fontSize: 20.0)),
              Expanded(
                // 为了方便拓展,我这边提取了 `snackBar` 的方法,并把按钮放在列表
                child: ListView(
      padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
         children: [ // SnackBar 需要提供一个包含 context,但是 context 不能是 Scaffold 节点下的 context,所以需要通过 Builder 包裹一层 Builder(builder: (context) => RaisedButton(onPressed: () => _changeValue(context), child: Text('修改当前值'))), ])) ]), // 当 SnackBar 弹出时,fab 会上移一段距离 floatingActionButton: Builder( builder: (context) => FloatingActionButton(onPressed: () => _changeValue(context), child: Icon(Icons.send))), ); } }
    • 效果图
      请注意看 fab和值的变化:
      【Flutter学习】基本组件之弹窗和提示(SnackBar、BottomSheet、Dialog)
  • BottomSheet

      BottomSheet看命名就知道是从底部弹出的菜单,展示 BottomSheet有两种方式,分别是 showBottomSheetshowModalBottomSheet,两种方式只有在展示类型上的差别,方法调用无差,而且 showBottomSheetfab有组合动画,showModalBottomSheet则没有,看下实际的例子吧。在 ListView中增加一个 BottomSheet的按钮,因为 BottomSheet需要的 context也不能是 Scaffold下的 context,所以需要通过 Builder进行包裹一层,然后增加 _showBottomSheet的方法
    • 示例方法  
      _showBottomSheet(BuildContext context) {
       showBottomSheet(
        context: context,
        builder: (context) => ListView(
        // 生成一个列表选择器
        children: List.generate(20,
      (index)
      => InkWell(
      child: Container(
      alignment: Alignment.center,
      height:
      60.0,
      child: Text('Item ${index + 1}')), onTap: () { print('tapped item ${index + 1}'); Navigator.pop(context); }//onTap
      ),//container ) //InkWell
      ),//generate );//ListView }

      showBottomSheet替换成 showModalBottomSheet就是另外一种展示方式了,内部不需要做任何改变。

    • 运行效果
      我们看下两种的运行效果:
      【Flutter学习】基本组件之弹窗和提示(SnackBar、BottomSheet、Dialog)
    • 拓展
      可以看到 showBottomSheet会充满整个屏幕,然后 fab会跟随一起到 AppBar的底部位置,而 showModalBottomSheet展示的高度不会超过半个屏幕的高度,但是 fab被其遮挡了。假如我们只需要展示 2-3 个 item,但是按照刚才的方式 showModalBottomSheet的高度太高了,那我们可以在 ListView外层包裹一层 Container,然后指定 height即可
      _showModalBottomSheet(BuildContext context) {
          showModalBottomSheet(
            context: context,
            builder: (context) => Container(
                  child: ListView(
                      children: List.generate(
                    2,
                    (index) => InkWell(
                        child: Container(alignment: Alignment.center, height: 60.0, child: Text('Item ${index + 1}')),
                        onTap: () {
                          print('tapped item ${index + 1}');
                          Navigator.pop(context);
                        }),
                  )),
                  height: 120,
                ),
          );
        }
      • 修改高度后的效果
        【Flutter学习】基本组件之弹窗和提示(SnackBar、BottomSheet、Dialog)
  • Dialog

      相对于 SnackBarBottomSheetDialog的使用场景相对会更多,在 MaterialDesign下,
          Dialog主要有 3 种:AlertDialogSimpleDialogAboutDialog,当然在 Cupertino风格下也有相应的 Dialog,因为这个系列以 MaterialDesign风格为主,所以
          Cupertiono等下次有时间再写吧。
    • AlertDialog

        在 ListView中增加一个 AlertDialog的按钮,用于点击显示 AlertDialog用,然后加入显示 AlertDilaog的方法,并将按钮的 onPressed指向该方法,Dialogcontext可以是 Scaffold下的 context,所以不需要用 Builder来包裹一层。
      • 示例代码
        _showAlertDialog() {
            showDialog(
                // 设置点击 dialog 外部不取消 dialog,默认能够取消
                barrierDismissible: false,
                context: context,
                builder: (context) => AlertDialog(
                      title: Text('我是个标题...嗯,标题..'),
                      titleTextStyle: TextStyle(color: Colors.purple), // 标题文字样式
                      content: Text(r'我是内容\(^o^)/~, 我是内容\(^o^)/~, 我是内容\(^o^)/~'),
                      contentTextStyle: TextStyle(color: Colors.green), // 内容文字样式
                      backgroundColor: CupertinoColors.white,
                      elevation: 8.0, // 投影的阴影高度
                      semanticLabel: 'Label', // 这个用于无障碍下弹出 dialog 的提示
                      shape: Border.all(),
                      // dialog 的操作按钮,actions 的个数尽量控制不要过多,否则会溢出 `Overflow`
                      actions: [
                        // 点击增加显示的值
                        FlatButton(onPressed: increase, child: Text('点我增加')),
                        // 点击减少显示的值
                        FlatButton(onPressed: decrease, child: Text('点我减少')),
                        // 点击关闭 dialog,需要通过 Navigator 进行操作
                        FlatButton(onPressed: () => Navigator.pop(context), 
                                   child: Text('你点我试试.')),
                      ],
                    ));
          }

         

      • 效果
        【Flutter学习】基本组件之弹窗和提示(SnackBar、BottomSheet、Dialog)

    • SimpleDialog

      SimpleDialog相比于 AlertDialog少了 contentaction参数,多了 children属性,需要传入 Widget列表,那就可以自定义全部内容了。那我们这里就实现一个性别选择的 Dialog,选择后通过 Taost提示选择的内容,Taost就是之前导入的第三方插件,只要实现 children 是个列表选择器就可以了。

      • 示例代码
        _showSimpleDialog() {
            showDialog(
                barrierDismissible: false,
                context: context,
                builder: (context) => SimpleDialog(
                      title: Text('我是个比较正经的标题...\n选择你的性别'),
                      // 这里传入一个选择器列表即可
                      children: _genders
                          .map((gender) => InkWell(
                                child: Container(height: 40.0, child: Text(gender), alignment: Alignment.center),
                                onTap: () {
                                  Navigator.pop(context);
                                  Fluttertoast.showToast(msg: '你选择的性别是 $gender');
                                },
                              ))
                          .toList(),
                    ));
          }

         

      • 效果
        【Flutter学习】基本组件之弹窗和提示(SnackBar、BottomSheet、Dialog)

 

 

    • AboutDialog

      AboutDialog主要是用于展示你的 App或者别的相关东西的内容信息的,平时用的比较少,显示 AboutDialog有两种方式可以展示,一种是前面一样的 showDialog方法,传入一个 AboutDialog实例,还有中方法是直接调用 showAboutDialog方法。我们还是一样在列表加个按钮,并指向显示 AboutDialog的事件。
      • 示例代码
        _showAboutDialog() {
            showDialog(
                barrierDismissible: false,
                context: context,
                builder: (context) => AboutDialog(
                      // App 的名字
                      applicationName: 'Flutter 入门指北',
                      // App 的版本号
                      applicationVersion: '0.1.1',
                      // App 基本信息下面会显示一行小字,主要用来显示版权信息
                      applicationLegalese: 'Copyright: this is a copyright notice topically',
                      // App 的图标
                      applicationIcon: Icon(Icons.android, size: 28.0, color: CupertinoColors.activeBlue),
                      // 任何你想展示的
                      children: [Text('我是个比较正经的对话框内容...你可以随便把我替换成任何部件,只要你喜欢(*^▽^*)')],
                    ));
          }

        也可以通过 showAboutDialog实现同样的效果

          _showAboutDialog() {
            showAboutDialog(
              context: context,
              applicationName: 'Flutter 入门指北',
              applicationVersion: '0.1.1',
              applicationLegalese: 'Copyright: this is a copyright notice topically',
              applicationIcon: Image.asset('images/app_icon.png', width: 40.0, height: 40.0),
              children: [Text('我是个比较正经的对话框内容...你可以随便把我替换成任何部件,只要你喜欢(*^▽^*)')],
            );
          }

         

      • 最后的效果:

        【Flutter学习】基本组件之弹窗和提示(SnackBar、BottomSheet、Dialog)
      • 拓展
        AboutDialog会自带两个按钮 VIEW LICENSESCLOSEVIEW LICENSES会跳转一个 Flutter Licenses的网页,CLOSE会关闭,至于为什么是英文的,是因为我们没有设置语言的原因,这个涉及到多语言。 

 

三,Dialog 状态保持

  假如有个需求,需要在弹出的 Dialog显示当前被改变的值,然后通过按钮可以修改这个值 ,该如何实现。相信很多小伙伴都会这么认为,通过 setState来修改不就行了吗,没错,我一开始的确这么去实现的,我们先看下代码好了,增加一个 DialogState按钮,然后指向对应的点击事件。

  • 示例代码
    _showStateDialog() {
        showDialog(
            context: context,
            barrierDismissible: false,
            builder: (context) => SimpleDialog(
                  title: Text('我这边能实时修改状态值'),
                  contentPadding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
                  children: [
                    Text('当前的值是: $_count', style: TextStyle(fontSize: 18.0)),
                    Padding(
                      padding: const EdgeInsets.symmetric(vertical: 12.0),
                      child: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
                        RaisedButton(
                          onPressed: increase,
                          child: Text('点我自增'),
                        ),
                        RaisedButton(
                          onPressed: decrease,
                          child: Text('点我自减'),
                        ),
                        RaisedButton(
                          onPressed: () => Navigator.pop(context),
                          child: Text('点我关闭'),
                        )
                      ]),
                    )
                  ],
                ));
      }

     

  • 效果

    【Flutter学习】基本组件之弹窗和提示(SnackBar、BottomSheet、Dialog)

  • 遇到问题
    怎么 Dialog的值不改变呢,明明界面上的已经修改了啊。所以说图样图森破咯,看下官方对 showDialog方法的解释吧
    /// This function takes a `builder` which typically builds a [Dialog] widget.
    /// Content below the dialog is dimmed with a [ModalBarrier]. The widget
    /// returned by the `builder` does not share a context with the location that
    /// `showDialog` is originally called from. Use a [StatefulBuilder] or a
    /// custom [StatefulWidget] if the dialog needs to update dynamically.
    糟糕透的翻译又来了:该方法通过 builder参数来传入一个 Dialog部件,dialog下的内容被一个「模态障碍」阻隔,builder的 context和调用 showDialog时候的 context不是共享的,如果需要动态修改 dialog的状态值,需要通过 StatefulBuilder或者自定义 dialog继承于 StatefulWidget来实现
  • 解决办法
    所以解决的方法很明确,对上面的代码进行修改,在外层嵌套一个 StatefulBuilder部件
     _showStateDialog() {
        showDialog(
            context: context,
            barrierDismissible: false,
            // 通过 StatefulBuilder 来保存 dialog 状态
            // builder 需要传入一个 BuildContext 和 StateSetter 类型参数
            // StateSetter 有一个 VoidCallback,修改状态的方法在这写
            builder: (context) => StatefulBuilder(
                builder: (context, dialogStateState) => SimpleDialog(
                      title: Text('我这边能实时修改状态值'),
                      contentPadding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
                      children: [
                        Text('当前的值是: $_count', style: TextStyle(fontSize: 18.0)),
                        Padding(
                          padding: const EdgeInsets.symmetric(vertical: 12.0),
                          child: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
                            RaisedButton(
                              // 通过 StatefulBuilder 的 StateSetter 来修改值
                              onPressed: () => dialogStateState(() => increase()),
                              child: Text('点我自增'),
                            ),
                            RaisedButton(
                              onPressed: () => dialogStateState(() => decrease()),
                              child: Text('点我自减'),
                            ),
                            RaisedButton(
                              onPressed: () => Navigator.pop(context),
                              child: Text('点我关闭'),
                            )
                          ]),
                        )
                      ],
                    )));
      }

     

  • 修改效果
      然后再运行下,可以看到 dialog和界面的值保持一致了
    【Flutter学习】基本组件之弹窗和提示(SnackBar、BottomSheet、Dialog)

 


 


推荐阅读
  • 在C#编程中,设计流畅的用户界面是一项重要的任务。本文分享了实现Fluent界面设计的技巧与方法,特别是通过编写领域特定语言(DSL)来简化字符串操作。我们探讨了如何在不使用`+`符号的情况下,通过方法链式调用来组合字符串,从而提高代码的可读性和维护性。文章还介绍了如何利用静态方法和扩展方法来实现这一目标,并提供了一些实用的示例代码。 ... [详细]
  • Unity3D 中 AsyncOperation 实现异步场景加载及进度显示优化技巧
    在Unity3D中,通过使用`AsyncOperation`可以实现高效的异步场景加载,并结合进度条显示来提升用户体验。本文详细介绍了如何利用`AsyncOperation`进行异步加载,并提供了优化技巧,包括进度条的动态更新和加载过程中的性能优化方法。此外,还探讨了如何处理加载过程中可能出现的异常情况,确保加载过程的稳定性和可靠性。 ... [详细]
  • 在Cisco IOS XR系统中,存在提供服务的服务器和使用这些服务的客户端。本文深入探讨了进程与线程状态转换机制,分析了其在系统性能优化中的关键作用,并提出了改进措施,以提高系统的响应速度和资源利用率。通过详细研究状态转换的各个环节,本文为开发人员和系统管理员提供了实用的指导,旨在提升整体系统效率和稳定性。 ... [详细]
  • 利用PHP循环高效处理多条帖子表单数据 ... [详细]
  • PHP预处理常量详解:如何定义与使用常量 ... [详细]
  • 本文深入解析了WCF Binding模型中的绑定元素,详细介绍了信道、信道管理器、信道监听器和信道工厂的概念与作用。从对象创建的角度来看,信道管理器负责信道的生成。具体而言,客户端的信道通过信道工厂进行实例化,而服务端则通过信道监听器来接收请求。文章还探讨了这些组件之间的交互机制及其在WCF通信中的重要性。 ... [详细]
  • Java并发机制详解及其在数据安全性保障中的应用方案 ... [详细]
  • 在 Axublog 1.1.0 版本的 `c_login.php` 文件中发现了一个严重的 SQL 注入漏洞。该漏洞允许攻击者通过操纵登录请求中的参数,注入恶意 SQL 代码,从而可能获取敏感信息或对数据库进行未授权操作。建议用户尽快更新到最新版本并采取相应的安全措施以防止潜在的风险。 ... [详细]
  • 基于 Vue 和 Element UI 实现的简洁登录界面设计
    本文介绍了一种利用 Vue.js 和 Element UI 框架构建的简洁登录界面设计。该设计不仅注重用户体验,还确保了界面的美观性和易用性。通过合理的布局和组件配置,实现了高效、响应式的登录功能,适用于多种前端应用场景。 ... [详细]
  • 本文探讨了如何利用Java代码获取当前本地操作系统中正在运行的进程列表及其详细信息。通过引入必要的包和类,开发者可以轻松地实现这一功能,为系统监控和管理提供有力支持。示例代码展示了具体实现方法,适用于需要了解系统进程状态的开发人员。 ... [详细]
  • 在PHP中实现腾讯云接口签名,以完成人脸核身功能的对接与签名配置时,需要注意将文档中的POST请求改为GET请求。具体步骤包括:使用你的`secretKey`生成签名字符串`$srcStr`,格式为`GET faceid.tencentcloudapi.com?`,确保参数正确拼接,避免因请求方法错误导致的签名问题。此外,还需关注API的其他参数要求,确保请求的完整性和安全性。 ... [详细]
  • 在Django中提交表单时遇到值错误问题如何解决?
    在Django项目中,当用户提交包含多个选择目标的表单时,可能会遇到值错误问题。本文将探讨如何通过优化表单处理逻辑和验证机制来有效解决这一问题,确保表单数据的准确性和完整性。 ... [详细]
  • AngularJS 进阶指南:第三部分深入解析
    在本文中,我们将深入探讨 AngularJS 的指令模型,特别是 `ng-model` 指令。`ng-model` 指令用于将 HTML 元素与应用程序数据进行双向绑定,支持多种数据类型验证,如数字、电子邮件地址和必填项检查。此外,我们还将介绍如何利用该指令优化表单验证和数据处理流程,提升开发效率和用户体验。 ... [详细]
  • 技术日志:使用 Ruby 爬虫抓取拉勾网职位数据并生成词云分析报告
    技术日志:使用 Ruby 爬虫抓取拉勾网职位数据并生成词云分析报告 ... [详细]
  • 利用 Zend Framework 实现高效邮件发送功能 ... [详细]
author-avatar
花长好月常圆人长久
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有