flutter的 dialog
一般会用到的dialog就是下面的showDialog函数。
使用方式一般就是:showDialog( 一个context,一个 builder),
Future<T> showDialog<T>({ @required BuildContext context, bool barrierDismissible = true, @Deprecated( 'Instead of using the "child" argument, return the child from a closure ' 'provided to the "builder" argument. This will ensure that the BuildContext ' 'is appropriate for widgets built in the dialog. ' 'This feature was deprecated after v0.2.3.' ) Widget child, WidgetBuilder builder, bool useRootNavigator = true, }) { assert(child == null || builder == null); assert(useRootNavigator != null); assert(debugCheckHasMaterialLocalizations(context)); final ThemeData theme = Theme.of(context, shadowThemeOnly: true); return showGeneralDialog( context: context, pageBuilder: (BuildContext buildContext, Animation<double> animation, Animation<double> secondaryAnimation) { final Widget pageChild = child ?? Builder(builder: builder); return SafeArea( child: Builder( builder: (BuildContext context) { return theme != null ? Theme(data: theme, child: pageChild) : pageChild; } ), ); }, barrierDismissible: barrierDismissible, barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, barrierColor: Colors.black54, transitionDuration: const Duration(milliseconds: 150), transitionBuilder: _buildMaterialDialogTransitions, useRootNavigator: useRootNavigator, ); }
使用的例子比如:
class MyHomePage extends StatelessWidget{
Widget build( BuildContext context) {
Widget current = Text('TESTTESTTEST', style: ts,);
current = Column(
mainAxisAlignment: MainAxisAlignment.center,
children: (){
var children = <Widget> [];
for(int i = 0; i < 10; ++i) {
var t = <Widget> [];
t.add(Spacer(flex: 1,));
t.add(current);
t.add(Spacer(flex: 1,));
children.add(Row(children: t,));
}
return children;}(),
);
current = Container (color: Colors.red, child: current, alignment: Alignment.center,);
var button = Container(alignment: Alignment.center, color: Colors.white, child: MaterialButton(child: Text('点我点我'),textColor: Colors.black, color: Colors.blue, onPressed: (){show(context);},));
current = Column(mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[Container(child: button, color: Colors.white, height: 80, width: double.infinity,), current,],);
current = Material(color: Colors.green, child: current,);
return current;
}
Future<void> show (BuildContext context) async {
showDialog(context: context, builder: (context) => SecondPage(),);
}
}
可以看到其中定义了一个show函数,在里面调用了showDialog方法,返回一个对话框。
直接生成页面的效果:
用showDialog里面生成页面的效果:
可以看到二者的关键区别就是dialog的屏幕上下方有留白,而普通的页面是不会有留白的。其中上下方的留白叫做safeArea,如果使用dialog是无法彻底去除这一点的,除非你这样,直接把showDialog方法重写一遍:
///重新实现的去掉SafeArea的ShowDialog方法,这样屏幕上下就不会留有无法填补的空白 Future<T> noSafeAreaShowDialog<T>({ @required BuildContext context, bool barrierDismissible = true, @Deprecated( 'Instead of using the "child" argument, return the child from a closure ' 'provided to the "builder" argument. This will ensure that the BuildContext ' 'is appropriate for widgets built in the dialog. ' 'This feature was deprecated after v0.2.3.') Widget child, WidgetBuilder builder, bool useRootNavigator = true, }) { assert(child == null || builder == null); assert(useRootNavigator != null); assert(debugCheckHasMaterialLocalizations(context)); final ThemeData theme = Theme.of(context, shadowThemeOnly: true); return showGeneralDialog( context: context, pageBuilder: (BuildContext buildContext, Animation<double> animation, Animation<double> secondaryAnimation) { final Widget pageChild = child ?? Builder(builder: builder); return Builder(builder: (BuildContext context) { return theme != null ? Theme(data: theme, child: pageChild) : pageChild; }); }, barrierDismissible: barrierDismissible, barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, barrierColor: Color.fromRGBO(0, 0, 0, 0.7), transitionDuration: const Duration(milliseconds: 150), useRootNavigator: useRootNavigator, );
看着好麻烦是吗?其实很简单,对比一下showDialog本身的方法源码:
Future<T> showDialog<T>({ @required BuildContext context, bool barrierDismissible = true, @Deprecated( 'Instead of using the "child" argument, return the child from a closure ' 'provided to the "builder" argument. This will ensure that the BuildContext ' 'is appropriate for widgets built in the dialog. ' 'This feature was deprecated after v0.2.3.' ) Widget child, WidgetBuilder builder, bool useRootNavigator = true, }) { assert(child == null || builder == null); assert(useRootNavigator != null); assert(debugCheckHasMaterialLocalizations(context)); final ThemeData theme = Theme.of(context, shadowThemeOnly: true); return showGeneralDialog( context: context, pageBuilder: (BuildContext buildContext, Animation<double> animation, Animation<double> secondaryAnimation) { final Widget pageChild = child ?? Builder(builder: builder); return SafeArea( child: Builder( builder: (BuildContext context) { return theme != null ? Theme(data: theme, child: pageChild) : pageChild; } ), ); }, barrierDismissible: barrierDismissible, barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, barrierColor: Colors.black54, transitionDuration: const Duration(milliseconds: 150), transitionBuilder: _buildMaterialDialogTransitions, useRootNavigator: useRootNavigator, );
就是把方法中的return safeArea改成了return showGeneralDialog,参数什么的都一样。这样就可以调用新的showDialog方法了。
另外还有一个方法,使用showModalBottomSheet可以很方便的从屏幕下方弹出对话框,不过这个就留到另一篇文章来说把。
进击的小🐴农