Dialog 是 material 风格的 widget。Dialog 定义了 最基本的属性。可以直接使用 Dialog 自定义 Dialog 的内容。
源码分析
Dialog 是一个 StatelessWidget widget ,所以只要了解他都组合了哪些 widget ,都起到了什么作用就好了。
dialog 样式
dialog 的样式 主要有三个属性 backgroundColor,elevation,shape
,分别对应背景色,阴影和形状。 最后决定属性值的是 参数,dialogTheme 和 defaults。
build 方法的前三句就是取样式的。
final ThemeData theme = Theme.of(context); final DialogTheme dialogTheme = DialogTheme.of(context); final DialogTheme defaults = theme.useMaterial3 ? _DialogDefaultsM3(context) : 复制代码
dialog 自身的参数优先级最高,其次是 dialogTheme
最后是 defaults
。你可能会疑问,后面两个值是哪里来的?
如果是全局的样式,可以在 MaterialApp 定义
MaterialApp( theme: ThemeData( dialogTheme: DialogTheme( alignment: Alignment.center, elevation: 6.0, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(28.0), topRight: Radius.circular(28.0), bottomLeft: Radius.circular(28.0), bottomRight: Radius.circular(28.0)))))) 复制代码
在 Dialog 的父级,用 Theme widget 也可以定义 dialogTheme。
如果没有定义 dialogTheme,会用默认值。_DialogDefaultsM3
和 _DialogDefaultsM2
都是 DialogTheme 的子类。规定了 Material Design 2 和 Material Design 3 的默认值。
useMaterial3 是一个临时变量,一旦 Design 3 成为稳定版,就都会使用 Design 3,useMaterial3 会被删除。
size
constraints: const BoxConstraints(minWidth: 280.0), 复制代码
dialog的最小宽度是280。高度根据内容自适应,一般不需要设置 dialog 的高度,除非内容太多,需要限制最大高度。
手机的宽度 一共也就 400 左右,最小宽度已经 限制为 280了,还得有 padding,所以宽度方面再大也很有限了,如果有精确匹配 child 宽度的需要,可以用 IntrinsicWidth 把 child 包起来。
如果想要宽度 小于 280,用 insetPadding 参数。
动画效果
final EdgeInsets effectivePadding = MediaQuery.of(context).viewInsets + (insetPadding ?? EdgeInsets.zero); return AnimatedPadding( padding: effectivePadding, duration: insetAnimationDuration, curve: insetAnimationCurve, ... 复制代码
最外层是用 AnimatedPadding 包裹的,它的用处主要是当 键盘弹起的时候,可以通过动画的方式让 dialog 向上弹起。viewInsets.bottom 的值是键盘的高度。可以通过参数 insetAnimationDuration 定义动画的 时间,参数 insetAnimationCurve 自定义动画的缓动曲线。
从这里可以看出,如果我们要改变 dialog 的大小,最好通过改变参数 insetPadding 的方式,因为这样会有动画效果。
使用 Dialog
源码已经分析完了,通过一个实例来看下如何用 Dialog。
showDialog( context: context, builder: (context) { return Dialog( child: Container( height: 200, color: Colors.green, child: ElevatedButton( child:const Text('close'), onPressed: () { Navigator.of(context).pop(); }, )), ); }); 复制代码
使用 showDialog
显示 dialog,用 Navigator.of(context).pop();
关闭 dialog。
Dialog 只是一个空壳,里面的内容可以完全自定义。
AlertDialog,SimpleDialog,是 Dialog 的子类,如果你的需求正好和他们匹配,也可以使用它们。
如果内容过高,用 SingleChildScrollView 包起来。
Dialog 只是 StatelessWidget,如果 child 需要保持状态用 StatefulWidget 包起来。