Flutter入门(34):Flutter 组件之 Dialog 弹框(Dialog,Alert)详解

1. 基本介绍

SimpleDialog、AlertDialog、CupertinoAlertDialog、Dialog 都是最常见的弹框提示。
CupertinoAlertDialog 是 iOS 风格弹框。
showDialog、showCupertinoDialog 是两个调用弹框的 api,基本没啥区别,使用也没有什么限制。

Dialog.gif

2. 示例代码

代码下载地址。如果对你有帮助的话记得给个关注,代码会根据我的 Flutter 专题不断更新。

3. 属性介绍

3.1 SimpleDialog 属性介绍

SimpleDialog属性 介绍
title 标题
titlePadding 标题外间距,默认为 const EdgeInsets.fromLTRB(24.0, 24.0, 24.0, 0.0),
titleTextStyle 标题样式 TextStyle
children 子控件,可以随意自定义
contentPadding 内容外间距,默认为 const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 16.0)
backgroundColor 背景色
elevation 阴影高度
semanticLabel 语义标签
shape 形状 ShapeBorder

3.2 AlertDialog 属性介绍

AlertDialog属性 介绍
title 标题
titlePadding 标题外间距,默认为 const EdgeInsets.fromLTRB(24.0, 24.0, 24.0, 0.0),
titleTextStyle 标题样式 TextStyle
content 内容控件
contentPadding 内容外间距,默认为 const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 24.0)
contentTextStyle 内容文本样式 TextStyle
actions 事件子控件组
actionsPadding 事件子控件间距,默认为 EdgeInsets.zero,
actionsOverflowDirection 事件过多时,竖向展示顺序,只有正向和反向,默认为 VerticalDirection.down
actionsOverflowButtonSpacing 事件过多时,竖向展示时,子控件间距
buttonPadding actions 中每个按钮边缘填充距离,默认为左右各 8.0
backgroundColor 背景色
elevation 阴影高度
semanticLabel 语义标签
insetPadding 对话框距离屏幕边缘间距,默认为 EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0)
clipBehavior 超出部分剪切方式,Clip.none
shape 形状 ShapeBorder
scrollable 是否可以滚动,默认为 false

3.3 CupertinoAlertDialog 属性介绍

CupertinoAlertDialog属性 介绍
title 标题
content 内容控件
actions 事件子控件组
scrollController 滚动控制器,内容超出高度,content 可以滑动
actionScrollController actions 滚动控制器,actions超出高度,actions 可以滑动
insetAnimationDuration 动画时间,默认为 const Duration(milliseconds: 100)
insetAnimationCurve 动画效果,渐进渐出等等,默认为 Curves.decelerate

3.4 Dialog 属性介绍

Dialog属性 介绍
backgroundColor 背景色
elevation 阴影高度
insetAnimationDuration 动画时间,默认为 const Duration(milliseconds: 100)
insetAnimationCurve 动画效果,渐进渐出等等,默认为 Curves.decelerate
insetPadding 对话框距离屏幕边缘间距,默认为 EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0)
clipBehavior 超出部分剪切方式,Clip.none
shape 形状 ShapeBorder
child 自定义弹框

4. Dialog调用方法详解

4.1 showDialog 详解

showDialog 是控制 Dialog 弹出的 api。下文有具体使用,这里就简单介绍一下常用属性。

showDialog常用属性 介绍
context 上下文
builder (context){ return widget;} 返回一个 Widget 作为弹框展示内容
barrierDismissible 点击背后蒙层是否关闭弹框,默认为 true
barrierColor 背后蒙层颜色
useSafeArea 是否使用安全区域,默认为 true
useRootNavigator 是否使用根导航,默认为 true
routeSettings 路由设置
child 子控件,和使用 builder 返回一个 widget 同样效果

4.2 showCupertinoDialog 详解

showCupertinoDialog 也是控制 Dialog 弹出的 api。其实与 showDialog 一样,两者都可以调用各种弹框,但是 showCupertinoDialog 默认是不可以点击空白区域隐藏的。

showCupertinoDialog常用属性 介绍
context 上下文
builder (context){ return widget;} 返回一个 Widget 作为弹框展示内容
useRootNavigator 是否使用根导航,默认为 true
barrierDismissible 点击背后蒙层是否关闭弹框,默认为 false
routeSettings 路由设置

5. SimpleDialog 详解

SimpleDialog 的属性都比较简单,下方写两个不同的 Dialog,备注基本写的很明白了,就不赘述了,不明白的属性可以参考最上方表格。

import 'package:flutter/material.dart';

class FMDialogVC extends StatefulWidget {
  @override
  FMDialogState createState() => FMDialogState();
}

class FMDialogState extends State <FMDialogVC> {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(title: Text("Dialog"),),
      body: ListView(
        padding: EdgeInsets.all(15),
        children: [
          _showDialog(context, "SimpleDialog - Normal", _simpleDialogForNormal(context)),

        ],
      ),
    );
  }

  RaisedButton _showDialog(context, title, dialog){
    return RaisedButton(
      child: Text("$title"),
      // 设置异步回调
      onPressed: () async {
        // 接收点击自己反参的值
        var result = await showDialog(
          context: context,
          barrierColor: Colors.red.withAlpha(30),
          barrierDismissible: true,
          // builder: (context){
          //   return dialog;
          // },
          child: dialog,
        );
        print(result);
      },
    );
  }

  SimpleDialog _simpleDialogForNormal(context){
    return SimpleDialog(
      title: Text("SimpleDialog - Normal"), // 标题
      titlePadding: EdgeInsets.fromLTRB(20, 20, 0, 0), // 标题外间距
      // 标题样式 TextStyle
      titleTextStyle: TextStyle(
        color: Colors.blue,
        fontSize: 25,
      ),
      contentPadding: EdgeInsets.only(left: 15, right: 15), // 内容外间距
      backgroundColor: Colors.white, // 背景色
      // 子控件,可以随意自定义
      children: [
        Container(
          child: Text("这就是最简单的 Dialog 了, 也可以在这里自定义样式。"),
          alignment: Alignment.center,
          padding: EdgeInsets.all(40),
        ),
        FlatButton(
          onPressed: (){
            // 隐藏弹框
            Navigator.pop(context, 'SimpleDialog - Normal, 我知道了');
          },
          child: Text("我知道了"),
          textColor: Colors.white,
          color: Colors.blue,
        ),
      ],
    );
  }
}
SimpleDialog - Normal.png
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(title: Text("Dialog"),),
      body: ListView(
        padding: EdgeInsets.all(15),
        children: [
          _showDialog(context, "SimpleDialog - Normal", _simpleDialogForNormal(context)),
          _showDialog(context, "SimpleDialog - Shape", _simpleDialogForShape(context)),
        ],
      ),
    );
  }

  SimpleDialog _simpleDialogForShape(context){
    return SimpleDialog(
      title: Text("SimpleDialog - Shape"), // 标题
      titlePadding: EdgeInsets.fromLTRB(20, 20, 0, 0), // 标题外间距
      // 标题样式 TextStyle
      titleTextStyle: TextStyle(
        color: Colors.blue,
        fontSize: 25,
      ),
      contentPadding: EdgeInsets.only(left: 15, right: 15), // 内容外间距
      backgroundColor: Colors.yellow, // 背景色
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(30),
        side: BorderSide(
          color: Colors.red,
          width: 1,
        ),
        
      ),
      // 子控件,可以随意自定义
      children: [
        Container(
          child: Text("这就是最简单的 Dialog 了, 也可以在这里自定义样式。"),
          alignment: Alignment.center,
          padding: EdgeInsets.all(40),
        ),
        FlatButton(
          onPressed: (){
            // 隐藏弹框
            Navigator.pop(context, 'SimpleDialog - Shape, 我知道了');
          },
          child: Text("我知道了"),
          textColor: Colors.white,
          color: Colors.blue,
        ),
      ],
    );
  }
SimpleDialog - Shape.png

6. AlertDialog 详解

AlertDialog 的属性都比较简单,下方写两个不同的 Dialog,备注基本写的很明白了,就不赘述了,不明白的属性可以参考最上方表格。

  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(title: Text("Dialog"),),
      body: ListView(
        padding: EdgeInsets.all(15),
        children: [
          _showDialog(context, "SimpleDialog - Normal", _simpleDialogForNormal(context)),
          _showDialog(context, "SimpleDialog - Shape", _simpleDialogForShape(context)),
          _showDialog(context, "AlertDialog - Normal", _alertDialogForNormal(context)),
          // _showDialog(context, "AlertDialog - Shape", _alertDialogForShape(context)),
        ],
      ),
    );
  }

  AlertDialog _alertDialogForNormal(context){
    return AlertDialog(
      title: Text("AlertDialog - Normal"), // 标题
      titlePadding: EdgeInsets.fromLTRB(20, 20, 0, 0), // 标题外间距
      // 标题样式 TextStyle
      titleTextStyle: TextStyle(
        color: Colors.blue,
        fontSize: 25,
      ),
      contentPadding: EdgeInsets.only(left: 15, right: 15), // 内容外间距
      // 内容样式 TextStyle
      contentTextStyle: TextStyle(
        color: Colors.grey,
        fontSize: 16,
      ),
      // 内容控件
      content: Container(
        height: 100,
        child: Column(
          children: [
            Padding(padding: EdgeInsets.all(15),),
            Text("这是最简单的 AlertDialog,也可以自定义样式"),
          ],
        ),
      ),

      backgroundColor: Colors.white, // 背景色

      actionsPadding: EdgeInsets.all(15), // 事件子控件间距
      // 事件子控件
      actions: [
        Text("也可以不放按钮的"),
        FlatButton(
          onPressed: (){
            Navigator.pop(context, 'AlertDialog - Normal, cancel');
          },
          child: Text("cancel")
        ),
        FlatButton(
          onPressed: (){
            Navigator.pop(context, 'AlertDialog - Normal, ok');
          },
          child: Text("ok"),
        ),
      ],
    );
  }
AlertDialog - Normal.png
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(title: Text("Dialog"),),
      body: ListView(
        padding: EdgeInsets.all(15),
        children: [
          _showDialog(context, "SimpleDialog - Normal", _simpleDialogForNormal(context)),
          _showDialog(context, "SimpleDialog - Shape", _simpleDialogForShape(context)),
          _showDialog(context, "AlertDialog - Normal", _alertDialogForNormal(context)),
          _showDialog(context, "AlertDialog - Shape", _alertDialogForShape(context)),
        ],
      ),
    );
  }

  AlertDialog _alertDialogForShape(context){
    return AlertDialog(
      title: Text("AlertDialog - Shape"), // 标题
      titlePadding: EdgeInsets.fromLTRB(20, 20, 0, 0), // 标题外间距
      // 标题样式 TextStyle
      titleTextStyle: TextStyle(
        color: Colors.blue,
        fontSize: 25,
      ),
      contentPadding: EdgeInsets.only(left: 15, right: 15), // 内容外间距
      // 内容样式 TextStyle
      contentTextStyle: TextStyle(
        color: Colors.grey,
        fontSize: 16,
      ),
      // 内容控件
      content: Container(
        height: 100,
        child: Column(
          children: [
            Padding(padding: EdgeInsets.all(15),),
            Text("这是最简单的 AlertDialog,也可以自定义样式"),
          ],
        ),
      ),

      backgroundColor: Colors.white, // 背景色

      actionsPadding: EdgeInsets.all(15), // 事件子控件间距
      // 事件子控件
      actions: [
        Text("也可以不放按钮的"),
        FlatButton(
            onPressed: (){
              Navigator.pop(context, 'AlertDialog - Shape, cancel');
            },
            child: Text("cancel")
        ),
        FlatButton(
          onPressed: (){
            Navigator.pop(context, 'AlertDialog - Shape, ok');
          },
          child: Text("ok"),
        ),
      ],
      // shape 形状
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(30),
        side: BorderSide(
          color: Colors.red,
          width: 1,
        ),

      ),
    );
  }
AlertDialog - Shape.png

7. CupertinoAlertDialog 详解

CupertinoAlertDialog 是一个 iOS 风格的弹出框,与其他弹框使用方式大同小异,就不细讲了。

7.1 使用 showCupertinoDialog 调用 api 展示 CupertinoAlertDialog 普通样式。

  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(title: Text("Dialog"),),
      body: ListView(
        padding: EdgeInsets.all(15),
        children: [
          _showDialog(context, "SimpleDialog - Normal", _simpleDialogForNormal(context)),
          _showDialog(context, "SimpleDialog - Shape", _simpleDialogForShape(context)),
          _showDialog(context, "AlertDialog - Normal", _alertDialogForNormal(context)),
          _showDialog(context, "AlertDialog - Shape", _alertDialogForShape(context)),
          _showCupertinoDialog(context, "CupertinoAlertDialog - Normal", _cupertinoAlertDialog(context)),
        ],
      ),
    );
  }

  // showCupertinoDialog 展示 Dialog,showCupertinoDialog 相比 showDialog 缺少部分属性,并且默认点击背景不隐藏
  RaisedButton _showCupertinoDialog(context, title, dialog){
    return RaisedButton(
      child: Text("$title"),
      onPressed: () async {
        var result = await showCupertinoDialog(
          context: context,
          builder: (context){
            return dialog;
          },
        );
      },
    );
  }

  CupertinoAlertDialog _cupertinoAlertDialog(context){
    return CupertinoAlertDialog(
      title: Text("CupertinoAlertDialog - Normal"),
      content: Container(
        height: 100,
        child: Column(
          children: [
            Padding(padding: EdgeInsets.all(15),),
            Text("这是最简单的 CupertinoAlertDialog,也可以自定义样式"),
          ],
        ),
      ),
      actions: [
        FlatButton(
            onPressed: (){
              Navigator.pop(context, 'CupertinoAlertDialog - Normal, cancel');
            },
            child: Text("cancel")
        ),
        FlatButton(
          onPressed: (){
            Navigator.pop(context, 'CupertinoAlertDialog - Normal, ok');
          },
          child: Text("ok"),
        ),
      ],
    );
  }
CupertinoAlertDialog - Normal.png

7.2 使用 showCupertinoDialog 调用 api 展示 CupertinoAlertDialog 多个按钮样式。

  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(title: Text("Dialog"),),
      body: ListView(
        padding: EdgeInsets.all(15),
        children: [
          _showDialog(context, "SimpleDialog - Normal", _simpleDialogForNormal(context)),
          _showDialog(context, "SimpleDialog - Shape", _simpleDialogForShape(context)),
          _showDialog(context, "AlertDialog - Normal", _alertDialogForNormal(context)),
          _showDialog(context, "AlertDialog - Shape", _alertDialogForShape(context)),
          _showCupertinoDialog(context, "CupertinoAlertDialog - Normal", _cupertinoAlertDialog(context)),
          _showCupertinoDialog(context, "CupertinoAlertDialog - Three", _cupertinoAlertDialogForThree(context)),
        ],
      ),
    );
  }

  CupertinoAlertDialog _cupertinoAlertDialogForThree(context){
    return CupertinoAlertDialog(
      title: Text("CupertinoAlertDialog - Normal"),
      content: Container(
        height: 100,
        child: Column(
          children: [
            Padding(padding: EdgeInsets.all(15),),
            Text("这是最简单的 CupertinoAlertDialog,也可以自定义样式"),
          ],
        ),
      ),
      actions: [
        FlatButton(
            onPressed: (){
              Navigator.pop(context, 'CupertinoAlertDialog - Three, cancel');
            },
            child: Text("cancel")
        ),
        FlatButton(
            onPressed: (){
              Navigator.pop(context, 'CupertinoAlertDialog - Three, delete');
            },
            child: Text(
              "delete",
              style: TextStyle(
                color: Colors.red,
              ),
            ),
        ),
        FlatButton(
          onPressed: (){
            Navigator.pop(context, 'CupertinoAlertDialog - Three, ok');
          },
          child: Text("ok"),
        ),
      ],
    );
  }
CupertinoAlertDialog - Three.png

7.3 使用 showDialog 调用 api 展示 CupertinoAlertDialog 多个按钮样式。

  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(title: Text("Dialog"),),
      body: ListView(
        padding: EdgeInsets.all(15),
        children: [
          _showDialog(context, "SimpleDialog - Normal", _simpleDialogForNormal(context)),
          _showDialog(context, "SimpleDialog - Shape", _simpleDialogForShape(context)),
          _showDialog(context, "AlertDialog - Normal", _alertDialogForNormal(context)),
          _showDialog(context, "AlertDialog - Shape", _alertDialogForShape(context)),
          _showCupertinoDialog(context, "CupertinoAlertDialog - Normal", _cupertinoAlertDialog(context)),
          _showCupertinoDialog(context, "CupertinoAlertDialog - Three", _cupertinoAlertDialogForThree(context)),
          _showDialog(context, "Use showDialog 展示 CupertinoAlertDialog - Normal", _cupertinoAlertDialog(context)),
        ],
      ),
    );
  }
showDialog - CupertinoAlertDialog.png

8. Dialog 详解

Dialog 是自由度最高的弹框,样式完全根据自己给 child 的值来展示,下边我就简单写一个自定义弹框。

  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(title: Text("Dialog"),),
      body: ListView(
        padding: EdgeInsets.all(15),
        children: [
          _showDialog(context, "SimpleDialog - Normal", _simpleDialogForNormal(context)),
          _showDialog(context, "SimpleDialog - Shape", _simpleDialogForShape(context)),
          _showDialog(context, "AlertDialog - Normal", _alertDialogForNormal(context)),
          _showDialog(context, "AlertDialog - Shape", _alertDialogForShape(context)),
          _showCupertinoDialog(context, "CupertinoAlertDialog - Normal", _cupertinoAlertDialog(context)),
          _showCupertinoDialog(context, "CupertinoAlertDialog - Three", _cupertinoAlertDialogForThree(context)),
          _showDialog(context, "Use showDialog 展示 CupertinoAlertDialog - Normal", _cupertinoAlertDialog(context)),
          _showDialog(context, "Dialog - Custom", _customDialog(context)),
        ],
      ),
    );
  }

  Dialog _customDialog(context){
    return Dialog(
      backgroundColor: Colors.yellow.shade100, // 背景色
      elevation: 4.0, // 阴影高度
      insetAnimationDuration: Duration(milliseconds: 300), // 动画时间
      insetAnimationCurve: Curves.decelerate, // 动画效果
      insetPadding: EdgeInsets.all(30), // 弹框距离屏幕边缘距离
      clipBehavior: Clip.none, // 剪切方式
      child: Container(
        width: 300,
        height: 300,
        color: Colors.white,
        alignment: Alignment.center,
        child: Column(
          children: [
            Text("Custom Dialog", style: TextStyle(color: Colors.blue, fontSize: 25),),
            Padding(padding: EdgeInsets.all(15)),
            Text("这是一个最简单的自定义 Custom Dialog"),
            Padding(padding: EdgeInsets.all(15),),
            FlatButton(
              onPressed: (){
                // 隐藏弹框
                Navigator.pop(context, 'SimpleDialog - Normal, 我知道了');
              },
              child: Text("我知道了"),
              textColor: Colors.white,
              color: Colors.blue,
            ),
          ],
        ),
      ),
    );
  }
Dialog custom.png

9. 技术小结

Dialog 是使用非常广泛的弹框,这里需要多加练习,其实更多的样式以及布局考验的仅仅是其他组件组合的基本功。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353