一,概述  

  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<PromptDemoPage> {
      var count = ; @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: )));
      } @override
      Widget build(BuildContext context) {
      return Scaffold(
      appBar: AppBar(
      title: Text('Prompt Demo'),
      ),
      body: Column(children: <Widget>[
      Text('当前值:$count', style: TextStyle(fontSize: 20.0)),
      Expanded(
      // 为了方便拓展,我这边提取了 `snackBar` 的方法,并把按钮放在列表
      child: ListView(
      padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
         children: <Widget>[
      // 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和值的变化:
  • 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(,
      (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就是另外一种展示方式了,内部不需要做任何改变。

    • 运行效果
      我们看下两种的运行效果:
    • 拓展
      可以看到 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(
      ,
      (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: ,
      ),
      );
      }
      • 修改高度后的效果
  • 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: <Widget>[
        // 点击增加显示的值
        FlatButton(onPressed: increase, child: Text('点我增加')),
        // 点击减少显示的值
        FlatButton(onPressed: decrease, child: Text('点我减少')),
        // 点击关闭 dialog,需要通过 Navigator 进行操作
        FlatButton(onPressed: () => Navigator.pop(context),
        child: Text('你点我试试.')),
        ],
        ));
        }
      • 效果

    • 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(),
        ));
        }
      • 效果

    • 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: <Widget>[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: <Widget>[Text('我是个比较正经的对话框内容...你可以随便把我替换成任何部件,只要你喜欢(*^▽^*)')],
        );
        }
      • 最后的效果:

      • 拓展
        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: <Widget>[
    Text('当前的值是: $_count', style: TextStyle(fontSize: 18.0)),
    Padding(
    padding: const EdgeInsets.symmetric(vertical: 12.0),
    child: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[
    RaisedButton(
    onPressed: increase,
    child: Text('点我自增'),
    ),
    RaisedButton(
    onPressed: decrease,
    child: Text('点我自减'),
    ),
    RaisedButton(
    onPressed: () => Navigator.pop(context),
    child: Text('点我关闭'),
    )
    ]),
    )
    ],
    ));
    }
  • 效果

  • 遇到问题
    怎么 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: <Widget>[
    Text('当前的值是: $_count', style: TextStyle(fontSize: 18.0)),
    Padding(
    padding: const EdgeInsets.symmetric(vertical: 12.0),
    child: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[
    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)的更多相关文章

  1. 【Flutter学习】组件通信(父子、兄弟)

    一,概述 flutter一个重要的特性就是组件化.组件分为两种状态,一种是StatefulWidget有状态组件,一种是StatelessWidget无状态组件. 无状态组件不能更新状态,有状态组件具 ...

  2. 【Flutter学习】组件学习之目录

    01. Flutter组件-Layout-Container-容器  02. Flutter组件-Text-Text-文本  03. Flutter组件-Text-RichText-富文本  04. ...

  3. Flutter学习笔记(10)--容器组件、图片组件

    如需转载,请注明出处:Flutter学习笔记(10)--容器组件.图片组件 上一篇Flutter学习笔记(9)--组件Widget我们说到了在Flutter中一个非常重要的理念"一切皆为组件 ...

  4. Flutter学习笔记(11)--文本组件、图标及按钮组件

    如需转载,请注明出处:Flutter学习笔记(10)--容器组件.图片组件 文本组件 文本组件(text)负责显示文本和定义显示样式,下表为text常见属性 Text组件属性及描述 属性名 类型 默认 ...

  5. Flutter学习笔记(13)--表单组件

    如需转载,请注明出处:Flutter学习笔记(13)--表单组件 表单组件是个包含表单元素的区域,表单元素允许用户输入内容,比如:文本区域,下拉表单,单选框.复选框等,常见的应用场景有:登陆.注册.输 ...

  6. Flutter学习笔记(15)--MaterialApp应用组件及routes路由详解

    如需转载,请注明出处:Flutter学习笔记(15)--MaterialApp应用组件及routes路由详解 最近一段时间生病了,整天往医院跑,也没状态学东西了,现在是好了不少了,也该继续学习啦!!! ...

  7. Flutter学习笔记(21)--TextField文本框组件和Card卡片组件

    如需转载,请注明出处:Flutter学习笔记(21)--TextField文本框组件和Card卡片组件 今天来学习下TextField文本框组件和Card卡片组件. 只要是应用程序就少不了交互,基本上 ...

  8. Flutter学习笔记(24)--SingleChildScrollView滚动组件

    如需转载,请注明出处:Flutter学习笔记(23)--多 在我们实际的项目开发中,经常会遇到页面UI内容过多,导致手机一屏展示不完的情况出现,以Android为例,在Android中遇到这类情况的做 ...

  9. 【Flutter学习】页面布局之基础布局组件

    一,概述 Flutter中拥有30多种预定义的布局widget,常用的有Container.Padding.Center.Flex.Row.Colum.ListView.GridView.按照< ...

随机推荐

  1. IAR MSP430怎么破解?IAR for MSP430安装注册破解激活图文详细教程

      IAR for MSP430全称IAR Embedded Workbench for MSP430,是一款功能强大的专业集成开发环境,软件包括项目管理.配置开发环境.创建编译器.定制具体编程方案等 ...

  2. 下载 GitHub 上保存在 AWS 的文件

    通过 GitHub 下载文件时,发现很多文件保存在亚马逊的 AWS 上.而国内访问 AWS 的速度很慢,经常会有文件下载失败.常用的解决方案是挂代理,但我这边挂了代理还是很慢,只好找其他办法. AWS ...

  3. Python笔记(十三)_os模块和os.path模块

    os模块中关于文件/目录常用的函数使用方法 getcwd() 返回当前工作目录 chdir(path) 改变工作目录 listdir(path='.') 列举指定目录中的文件名('.'表示当前目录,' ...

  4. Play with Chain 【HDU - 3487】【Splay+TLE讲解】

    题目链接 很好的一道题,用了三天多的时间,终于知道了我为什么T的原因,也知道了在Splay的同时该怎样子的节约时间,因为Splay本身就是大常数的O(N*logN),我们如果不在各种细节上节约时间,很 ...

  5. MySQL 查询语句--------------进阶9:联合查询

    #进阶9:联合查询 /* union 联合 合并:将多条查询语句的结果合并成一个结果 语法: 查询语句1 union 查询语句2 union..... 应用场景:要查询的结果来自于多个表,且多个表没有 ...

  6. Logistic Regression Algorithm解决分类问题

    在线性回归算法中,我们看到,在training set中,输入矩阵X与向量y的值都是连续的.所以在二维空间中,我们可以用一条直线去模拟X与y的变化关系,寻找参数向量theta的取值.如根据房屋面积预测 ...

  7. onblur和onkeyup事件

    onblur:事件会在对象失去焦点时发生 提示:onblur 相反事件为onfocus事件 . onkeyup: 事件会在键盘按键被松开时发生. 提示:与onkeyup 事件相关的事件发生次序: on ...

  8. Array.prototype.includes

    if (!Array.prototype.includes) {   Array.prototype.includes = function(searchElement /*, fromIndex*/ ...

  9. Oracle PL/SQL基础

    1.下载sql developer数据库连接可视化工具 连接地址:点我下载 下载完成,安装有Java环境,解压即可运行,也可以在linux系统中运行.

  10. Hibernate使用时需要注意的几个小问题

    今天晚上玩了一下JDBC连接数据库,之后又利用Hibernate进行了数据库的访问,感觉利用Hibernate对数据库访问在文件配置好了之后确实更加简单快捷. 但是在操作的过程中也有一些细节需要注意一 ...