如何自定义对话框的位置、大小和背景?

How to customize a dialog's position, size and background?

我有一个带有 FAB 的主屏幕,按下它时我想显示一个对话框供用户输入。

目前我正在使用 showDialog() 和 SimpleDialog。

showDialog(
  context: context,
  builder: (BuildContext context) {
    return SimpleDialog(
      title: NormalText('New Counter Item'),
      contentPadding: EdgeInsets.fromLTRB(24.0, 0.0, 24.0, 24.0),
      children: <Widget>[
        Container(
          ...
        )
      ],
    );
  }
);

但是,我似乎无法用它自定义几乎任何东西(更小、弯曲的角和位于屏幕下方的位置)。 AlertDialog好像是一样的

是否可以自定义这些属性?

没有。这些不是设计为可定制的。它们是为了尊重 Material 设计原则而设计的。

如果您想要定制设计,您可以根据 Align and/or DecoratedBox

制作自己的模态

SimpleDialogAlertDialog 旨在满足一组特定的需求。它们具有一定程度的自定义,但最终它们只是为了显示简单的 pop-up 对话框,为用户提供一些信息并提示对话响应(即 "Yes"、"No"、"Cancel", "Save", 等等).

如果您想要自定义程度更高的 pop-up 对话框,您需要创建自己的对话框。不过,从好的方面来说,它真的很简单。将 showDialog return 中的构建器与 child 的 Dialog 小部件设置为您想要的任何值:

showDialog(
  context: context,
  builder: (BuildContext cxt) {
    return Dialog(
      child: Container(
        ...
      ),
    );
  },
);

显然,您需要重新创建标题栏和操作栏等内容,但您可以破解 SimpleDialogAlertDialog 的源代码并复制其中的内容,或者你可以推出自己的解决方案。

它并没有你想象的那么可怕。 您只需要克隆 Dialog.dart,然后 用对齐替换中心小部件。

当然也要重命名东西;例如MyDialog、myShowDialog、MySimpleDialog。

是的,就这么简单。

而且,如果您正在滚动,如何添加对齐小部件的对齐参数作为额外...

return showDialog<void>(
      barrierDismissible: true,
      context: context,
      builder: (BuildContext context) {
        return new Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(0),
              child: new Container(
                height: 100,
                width: MediaQuery.of(context).size.width,
                color: Colors.purple,
                child: new Column(
                  children: <Widget>[
                    new Text(
                      'custom dialog text',
                      style: new TextStyle(
                        fontSize: 14,
                        color: Colors.white,
                      ),
                    ),
                  ],
                ),
              ),
            )
          ],
        );
      },
    );

希望这对您有所帮助, 谢谢

这是一个干净的解决方案,如果由于某种原因你有一个 TextField/TextFormField 并且在那里你有一个 onsubmit 属性 那么你可以按照:

onSubmit: () {                   
    showDialog(
      context: context,
      builder: (context){
        return WillPopScope(
          onWillPop: () { return Future(() => false); }, // this will prevent going back 
          child: AlertDialog(
            content: Row(
              children: [
                progressWidget(),
                Container(margin: EdgeInsets.only(left: 10.0),child:Text("Loading" )),
              ],),
          )
        );
      }
    );

    yourCallToMethod.whenComplete((){
      Navigator.of(context).pop();
    });
},

好处?

当显示 showAlert 时,如果有人随意或粗暴地点击屏幕,屏幕就会返回。这可以防止这种行为,并且仅在您的函数完成时关闭 showAlert

您实际上可以通过在构建器中添加一个 SingleChildScrollView() + 一个填充(用于距顶部的偏移量)来修改它的位置(仅高度),如下所示:

showDialog<String>(
  context: context,
  builder: (ctxDialog) =>
    SingleChildScrollView(
      child: Padding(
        padding: EdgeInsets.only(top: 150.0),
        child: AlertDialog()
      )
    )
);

不管接受的答案是什么;有多种方法可以按照您要求的方式自定义 SimpleDialog。

尺码

SimpleDialog 将在 width/height 中增长,具体取决于子项及其填充方式。下面的代码将生成一个宽度为 336,高度为 300 的对话框:

showDialog(
  context: context,
  builder: (BuildContext context) {
    return SimpleDialog(
      insetPadding: EdgeInsets.zero,
      titlePadding: EdgeInsets.zero,
      contentPadding: EdgeInsets.zero,
      children: [
        Container(
          width: 300,
          height: 300,
        ),
      ],
    );
  },
);

不确定在宽度上增加的 36 像素是多少;但这表明尺寸 可以 定制。

角落

可以使用 shape 属性 自定义角。下面的代码显示了一个带有 4 像素圆边的绿色边框:

showDialog(
  context: context,
  builder: (BuildContext context) {
    return SimpleDialog(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(4.0),
        side: BorderSide(
          color: Colors.green,
        ),
      ),
      /* ... */
    );
  },
);

位置

我发现我可以使用 insetPadding 属性 在页面上上下移动对话框。这定义了屏幕边缘和对话框之间所需的最小 space 量。虽然有点麻烦,但如果你知道屏幕的大小和对话框的大小,你可以用一些简单的数学来微调对话框的位置。

给定 1920 像素的屏幕高度和 300 像素的对话框高度,下面的代码应将您的对话框放置在距离屏幕顶部边缘 100 像素的位置,而不是在中心爆炸:

showDialog(
  context: context,
  builder: (BuildContext context) {
    return SimpleDialog(
      insetPadding: EdgeInsets.only(bottom: 1520),
      /* ... */
    );
  },
);

这是因为我要求屏幕底部边缘和对话框之间的间距最小;在这个规定下,对话框唯一存在的位置是靠近顶部。

:- 我们可以通过给底部改变对话框的垂直位置 insetPadding 喜欢

insetPadding: EdgeInsets.only(bottom: XX);

:- 和水平位置由水平填充或左

insetPadding: EdgeInsets.symmetric(horizontal:XX);
or
insetPadding: EdgeInsets.only(left: XX,right:YY);

解决了在 StackPositioned

中包装对话框主体的问题
Stack(
                        children: [
                          Positioned(
                            left: 100, // left coordinate
                            top: 100,  // top coordinate
                            child: YOUR_DIALOG....