一,概述  

  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. JS-计算身份证校验码(最后一位)

    在线预览 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...

  2. python numpy求四分位距

    import numpy as np ages=[3,3,6,7,7,10,10,10,11,13,30] lower_q=np.quantile(ages,0.25,interpolation='l ...

  3. Spark SQL实战

    一.程序 package sparklearning import org.apache.log4j.Logger import org.apache.spark.SparkConf import o ...

  4. Dapper(一) 简介和性能

    Dapper的简介 Dapper是.NET下一个micro的ORM,它和Entity Framework或Nhibnate不同,属于轻量级的,并且是半自动的.Dapper只有一个代码文件,完全开源,你 ...

  5. 16/8/23_CSS自动换行

    转载:http://blog.csdn.net/ye987987/article/details/8011875   自动换行问题,正常字符的换行是比较合理的,而连续的数字和英文字符常常将容器撑大,挺 ...

  6. php Function ereg() is deprecated的解决方法

    PHP 5.3 ereg() 无法正常使用,提示“Function ereg() is deprecated Error”.问题根源是php中有两种正则表示方法,一个是posix,一个是perl,ph ...

  7. upc 组队赛18 STRENGTH【贪心模拟】

    STRENGTH 题目链接 题目描述 Strength gives you the confidence within yourself to overcome any fears, challeng ...

  8. 编程语言 - PHP

    环境搭建 Window7+Apache24+PHP7. Apache24配置 LoadModule php7_module "D:/SoftWare/php-7.2.21-Win32-VC1 ...

  9. php的优势与缺点

    PHP即“超文本预处理器”,是一种通用开源脚本语言.PHP是在服务器端执行的脚本语言,与C语言类似,是常用的网站编程语言.PHP独特的语法混合了C.Java.Perl以及 PHP 自创的语法.利于学习 ...

  10. JS面向对象——工厂模型

    工厂模型抽象了创建具体对象的过程,以下示例代码说明工厂类型: <!DOCTYPE html> <html> <head> <title>工厂模型< ...