【问题标题】:How to customize a dialog's position, size and background?如何自定义对话框的位置、大小和背景?
【发布时间】:2018-08-20 11:43:24
【问题描述】:

我有一个带有 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 好像是一样的。

是否有自定义这些属性?

【问题讨论】:

    标签: flutter flutter-layout


    【解决方案1】:
    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,
                          ),
                        ),
                      ],
                    ),
                  ),
                )
              ],
            );
          },
        );
    

    希望这会有所帮助, 谢谢

    【讨论】:

    • 我想创建一个固定大小为 150 x 150 像素的 showDialog。我已将容器宽度和高度更新为 return Container( height: 150, width: 150, );但仍然无法正常工作。我得到的是 3:2 比例的矩形框,而不是方形份额。任何建议。
    【解决方案2】:

    没有。这些并非设计为可定制的。他们在设计时考虑到了 Material Design 原则。

    如果您想要自定义设计,您可以根据 Align 和/或 DecoratedBox 制作自己的模态

    【讨论】:

    • 我在想,this talk 不是在宣传他们可以轻松地为每个品牌定制一切以拥有自己的设计吗?当然,MD 原则并没有规定像对话框的角半径这样基本的东西。
    • 您误解了可定制的含义。他们提供了一些选择。但最终,如果你想要一个完全不同的设计,不妨重新创造它。这样你就可以从你的项目中删除import "package:flutter/material.dart"
    • 我想创建一个固定大小为 150 x 150 像素的 showDialog。我已将容器宽度和高度更新为 return Container(height: 150, width: 150, );但仍然无法正常工作。我得到的是 3:2 比例的矩形框,而不是方形份额。任何建议。
    【解决方案3】:

    SimpleDialogAlertDialog 旨在满足特定的需求。它们有一定程度的定制,但最终它们只是为了显示简单的弹出对话框,为用户提供一些信息并提示对话框响应(即“是”、“否”、“取消”、“保存”、等等)。

    如果您想要一个更可定制的弹出对话框,您将需要创建自己的。不过,从好的方面来说,它真的很简单。让 showDialog 中的构建器返回一个 Dialog 小部件,其中的子级设置为您想要的任何内容:

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

    显然,您将需要重新创建标题栏和操作栏等内容,但您可以打开 SimpleDialogAlertDialog 的源代码并复制它们那里的内容,或者您​​可以推出自己的解决方案.

    【讨论】:

      【解决方案4】:

      这并不像你想象的那么可怕。 你只需要克隆 Dialog.dart,然后 将 Center 小部件替换为 Align。

      当然也可以重命名东西;例如我的对话,我的显示对话,我的简单对话。

      是的,就是这么简单。

      如果你在滚动,添加 Align 小部件的对齐参数作为一个额外的参数怎么样......

      【讨论】:

      • 事实上,如果团队将 AlignedDialog 添加到 dialog.dart 以节省我们的麻烦 ;-)
      【解决方案5】:

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

      尺寸

      SimpleDialog 的宽度/高度会根据子级及其填充方式而增长。下面的代码将生成一个宽度为 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 属性在页面上上下移动对话框。这定义了屏幕边缘和对话框之间所需的最小空间量。虽然有点麻烦,但如果你知道屏幕的大小和对话框的大小,你可以用一些简单的数学来微调对话框的位置。

      假设屏幕高度为 1920 像素,对话框高度为 300 像素,以下代码应将对话框放置在距屏幕顶部边缘 100 像素的位置,而不是在中心位置:

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

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

      【讨论】:

      • 我想创建一个固定大小为 150 x 150 像素的 showDialog。我已将容器宽度和高度更新为 return Container(height: 150, width: 150, );但仍然无法正常工作。我得到的是 3:2 比例的矩形框,而不是方形份额。任何建议。
      • @Kamlesh 正如答案中提到的,Flutter 似乎为对话框增加了额外的宽度。我不太确定为什么会发生这种情况,但是您可能仍然可以通过从您声明的宽度中删除一些像素来欺骗布局以显示一个方形对话框。不理想,但不幸的是我没有时间研究差异。
      • 老实说,这些都是 hack,还不如使用你自己的对话框
      • @Ced 诚实是好的,但我认为这些是否是all hacks 是值得商榷的。最容易维护的代码是无代码,所以如果这些代码完全实现了某人想要的,那么从头开始编写一些东西是没有意义的。所以要看个人情况。
      • 不明确其意图的代码更难维护
      【解决方案6】:

      这是一个干净的解决方案,如果由于某种原因你有一个 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

      【讨论】:

      • 您可以使用showGeneralDialog&lt;T&gt;函数并设置isBarrierDismissible: true来阻止用户关闭对话框。
      【解决方案7】:

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

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

      【讨论】:

        【解决方案8】:

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

        insetPadding: EdgeInsets.only(bottom: XX);
        

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-11-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多