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可以很方便的从屏幕下方弹出对话框,不过这个就留到另一篇文章来说把。

posted @ 2020-08-06 21:14  NeoZy  阅读(722)  评论(0编辑  收藏  举报