【问题标题】:Flutter: How to change the width of an AlertDialog?Flutter:如何更改 AlertDialog 的宽度?
【发布时间】:2019-05-23 14:28:07
【问题描述】:

我想知道如何更改AlertDialog的默认宽度,我只成功更改了边框半径:

这是我的代码:

showDialog(
       context: context,
       builder: (_) =>
            new AlertDialog(
               shape: RoundedRectangleBorder(
                   borderRadius: BorderRadius.all(Radius.circular(10.0))
               ),
               content: ProductPreviewScreen(),
            )
    );

预期结果:

有什么想法吗?

【问题讨论】:

    标签: flutter dart flutter-layout


    【解决方案1】:

    您可以尝试按照here 中的建议使用 ConstrainedBox 小部件包装您的 AlertDialog 小部件,并为 maxWidth 参数设置所需的值。

    更新

    我刚刚查看了 AlertDialog 小部件的父级代码,即 Dialog 小部件,发现它用一个最小宽度为 280 像素的 ConstrainedBox 小部件包装了它的子级。这就是我们不能改变 AlertDialog 小部件宽度的原因。

    幸运的是,我们可以做两件事。第一个选项是更改 dialog.dart 文件中 Dialog Widget 的默认 minWidth。请注意,更改此设置会影响所有使用 Dialog 小部件的颤振项目。

    //inside dialog.dart
    
    class Dialog extends StatelessWidget {
    
    ...
    
    @override
    Widget build(BuildContext context) {
      final DialogTheme dialogTheme = DialogTheme.of(context);
      return AnimatedPadding(
        padding: MediaQuery.of(context).viewInsets + const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0),
        duration: insetAnimationDuration,
        curve: insetAnimationCurve,
        child: MediaQuery.removeViewInsets(
          removeLeft: true,
          removeTop: true,
          removeRight: true,
          removeBottom: true,
          context: context,
          child: Center(
            child: ConstrainedBox(
              constraints: const BoxConstraints(minWidth: 280.0), // You can set your desired value for minWidth here
              child: Material(
                elevation: 24.0,
    
                ...
    

    然后您可以像这样使用 AlertDialog:

    showDialog(
      context: context,
      builder: (_) => AlertDialog(
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.all(Radius.circular(10.0))
          ),
        contentPadding: EdgeInsets.all(0.0),
        content: ProductPreviewScreen(),
        )
      )
    );
    

    另一种方法是创建我们自己的自定义对话框。

    showDialog(
      context: context,
      builder: (_) => Center( // Aligns the container to center
        child: Container( // A simplified version of dialog. 
          width: 100.0,
          height: 56.0,
          color: Colors.pink,
          )
        )
     );
    

    【讨论】:

    • 我尝试用 Center 小部件或 Align 小部件包装 ConstrainedBox。它确实改变了宽度,但有些东西是关闭的。我还将 AlertDialog 的 contentPadding 参数设置为零,它消除了 AlertDialog 中内容的默认填充。
    • @JeromeEscalante 我尝试将它包装在一个中心小部件中,并使用 minWidth,但它仍然无法正常工作.. 当您尝试时宽度是否发生了变化?
    • 我认为材料警报对话框无法做到这一点。您可以编写自己的对话框来实现这一点。我认为材料警报对话框已经是固定大小的小部件。
    • @Julien,我认为 Janpan 是对的。要么我们创建自己的自定义对话框并使用 showDialog 函数显示它,要么我们可以在 dialog.dart 文件中更改 Dialog 小部件的某些参数。
    【解决方案2】:

    使用内置对话框:

    • 增加宽度:

      AlertDialog(
        title: Text("AlertDialog"),
        insetPadding: EdgeInsets.zero,
      )
      
    • 减小宽度:

      AlertDialog(
        title: Text("AlertDialog"),
        insetPadding: EdgeInsets.symmetric(horizontal: 100),
      )
      

    使用自定义对话框:

    调用这个方法:

    showGeneralDialog(
      context: context,
      barrierColor: Colors.black.withOpacity(0.5),
      pageBuilder: (_, __, ___) {
        return Material(
          color: Colors.transparent,
          child: Center(
            child: Container(
              color: Colors.white, // Dialog background
              width: 120, // Dialog width
              height: 50, // Dialog height
              child: SingleChildScrollView(
                child: Column(
                  children: [
                    Text('I am a small Dialog'),
                  ],
                ),
              ),
            ),
          ),
        );
      },
    );
    

    【讨论】:

    • 我想制作 200 x 200 像素的对话框。我该怎么做?请建议。谢谢。
    • @Kamlesh 到目前为止,您无法使用AlertDialog 做到这一点,您必须创建自己的小部件。请参阅this answer 以开始使用。
    • 我喜欢简短的答案!
    • @Kamlesh 我还没有尝试过,但我认为对于您的情况,您可能希望在您选择的大小的 ContainerSizedBox 中使用 dailog。
    【解决方案3】:

    我的解决方案是将 Dialog 包含在一个小部件中,该小部件通过修改 MediaQueryData 来消除 Dialog 类添加的额外填充。

    import 'package:myapp/widgets/dialog_inset_defeat.dart';
    ...
    
    showDialog(
        context: context,
        builder: (_) => DialogInsetDefeat(
          context: context,
          child: SimpleDialog(...),
        )
    );
    

    ... 或使用 showDialogWithInsets() 获取自定义值:

    showDialogWithInsets(
        context: context,
        edgeInsets: EdgeInsets.symmetric(horizontal: 8),
        builder: (_) => SimpleDialog(...),
        )
    );
    

    文件 dialog_inset_defeat.dart

       import 'package:flutter/material.dart';
    
    /// A widget to defeat the hard coded insets of the [Dialog] class which
    /// are [EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0)].
    ///
    /// See also:
    ///
    ///  * [Dialog], for dialogs that have a message and some buttons.
    ///  * [showDialog], which actually displays the dialog and returns its result.
    ///  * <https://material.io/design/components/dialogs.html>
    ///  * <https://stackoverflow.com/questions/53913192/flutter-change-the-width-of-an-alertdialog>
    class DialogInsetDefeat extends StatelessWidget {
      final BuildContext context;
      final Widget child;
      final deInset = EdgeInsets.symmetric(horizontal: -40, vertical: -24);
      final EdgeInsets edgeInsets;
    
      DialogInsetDefeat({@required this.context, @required this.child, this.edgeInsets});
    
      @override
      Widget build(BuildContext context) {
        var netEdgeInsets = deInset + (edgeInsets ?? EdgeInsets.zero);
        return MediaQuery(
          data: MediaQuery.of(context).copyWith(viewInsets: netEdgeInsets),
          child: child,
        );
      }
    }
    
    /// Displays a Material dialog using the above DialogInsetDefeat class.
    /// Meant to be a drop-in replacement for showDialog().
    ///
    /// See also:
    ///
    ///  * [Dialog], on which [SimpleDialog] and [AlertDialog] are based.
    ///  * [showDialog], which allows for customization of the dialog popup.
    ///  * <https://material.io/design/components/dialogs.html>
    Future<T> showDialogWithInsets<T>({
      @required BuildContext context,
      bool barrierDismissible = true,
      @required WidgetBuilder builder,
      EdgeInsets edgeInsets,
    }) {
      return showDialog(
        context: context,
        builder: (_) => DialogInsetDefeat(
          context: context,
          edgeInsets: edgeInsets,
          child: Builder(builder: builder),
        ),
        // Edited! barrierDismissible: barrierDismissible = true,
        barrierDismissible: barrierDismissible,
      );
    }
    

    从 Flutter 1.8.3 开始为我工作。 YMMV

    【讨论】:

    • 请注意,这确实是一个绕过工具包中硬编码值的工具。更高版本的 Flutter 可能会提供更大的灵活性。它确实尝试使用现有框架而不是替换它,尽管每个解决方案都有它的位置。
    • @Crec Beback 无法通过敲出容器来关闭
    • @shinriyo 我有一段时间没有测试了。查看我的代码(仅通过视觉),我希望总是出现“barrierDismissible”的相反错误。我已经在上面更新了。
    • Gyuri Majercsik 建议我的解决方案不处理键盘插入,并且可以通过将 MediaQuery.of(context).viewInsets 添加到 netEdeInsets 来轻松修复当前上下文插入。我无法测试,但假设如果不是真的,他不会添加这个。
    • 我要制作 200 x 200 像素的固定大小对话框。我该怎么做?请建议。谢谢。
    【解决方案4】:

    使用填充小部件

     Padding(
       padding: EdgeInsets.only(left: 50.0, right: 50.0),
       child://AlertDialog or any other Dialog you can use
             Dialog(
                    elevation: 0.0,
                    backgroundColor: Colors.transparent,
                    child: Container(
                      width: 10.0,
                      height: 50.0,
                      color: Colors.red,
                    )
                ))
    

    【讨论】:

    • 添加填充顶层...Padding(padding: "..",child:
    【解决方案5】:

    这比其他答案要简单得多。只需使用构建器来更改正在构建的对话框的大小(构建,用其他语言实例化)。这意味着您还可以查询屏幕尺寸并根据所述屏幕尺寸决定您想要多少空间。例如,平板电脑上的空间比手机上的空间大。如果需要 App bar 等功能,可以将 Scaffold 设为 Container 的子级。

    showDialog(
      context: context,
      builder: (_) => new AlertDialog(
      shape: RoundedRectangleBorder(
        borderRadius:
          BorderRadius.all(
            Radius.circular(10.0))),
        content: Builder(
          builder: (context) {
            // Get available height and width of the build area of this widget. Make a choice depending on the size.                              
            var height = MediaQuery.of(context).size.height;
            var width = MediaQuery.of(context).size.width;
    
            return Container(
              height: height - 400,
              width: width - 400,
            );
          },
        ),
      )
    );
    

    不同尺寸的例子:

    可选择添加这些以删除不需要的内/外边框空间。

              insetPadding: EdgeInsets.zero,
              contentPadding: EdgeInsets.zero,
              clipBehavior: Clip.antiAliasWithSaveLayer,
    

    【讨论】:

    • 内边距太大。
    • Shinriyo 这是一个例子。不要复制大小完全更改以满足您的需求。
    • 很抱歉,但对我不起作用。谢谢。
    • Kamlesh 我仍然每天在我的应用程序中使用此代码。在这里工作。也许你错过了什么,应该重新检查
    • @Kent 我想创建一个固定大小的 150 x 150 像素的 showDialog。我已将容器宽度和高度更新为 return Container(height: 150, width: 150, );但仍然无法正常工作。我得到的是 3:2 比例的矩形框,而不是方形份额。任何建议。
    【解决方案6】:

    作为一种解决方法,您可以使用对话框标题,在大多数情况下,对话框会水平扩展以适应标题。因此,您可以创建大标题以确保对话框将采用最大宽度。显然你不能只放长标题,但你可以建立两个文本小部件的标题,其中一个具有文本颜色匹配背景。对于不显示标题的情况:

    showDialog(
       context: context,
       builder: (_) =>
            new AlertDialog(
               title: Text('hidden title, just set font text to the same as background.',
                     style: TextStyle(color: Colors.white)),
               shape: RoundedRectangleBorder(
                   borderRadius: BorderRadius.all(Radius.circular(10.0))
               ),
               content: ProductPreviewScreen(),
            )
    );
    

    【讨论】:

      【解决方案7】:

      自 2020 年 5 月起,如果您想更改对话框的内边距,您只需使用 Dialog 类并覆盖“insetPadding”属性即可。如果您愿意,可以让对话框一直延伸到屏幕边缘。

      您还可以通过使对话框表面本身透明来制作一些很酷的自定义对话框,然后添加您想要的任何小部件。例如:

      showDialog(Dialog(
        backgroundColor: Colors.transparent,
        insetPadding: EdgeInsets.all(10),
        child: Stack(
          overflow: Overflow.visible,
          alignment: Alignment.center,
          children: <Widget>[
            Container(
              width: double.infinity,
              height: 200,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(15),
                color: Colors.lightBlue
              ),
              padding: EdgeInsets.fromLTRB(20, 50, 20, 20),
              child: Text("You can make cool stuff!",
                style: TextStyle(fontSize: 24),
                textAlign: TextAlign.center
              ),
            ),
            Positioned(
              top: -100,
              child: Image.network("https://i.imgur.com/2yaf2wb.png", width: 150, height: 150)
            )
          ],
        )
      ));
      

      结果:

      【讨论】:

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

      您可以更改 AlertDialog 属性 insetPadding 这对您来说是一种简单的方法。

       void alertBox() {
          showDialog(
            context: context,
            builder: (context) => AlertDialog(
              insetPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
              // (horizontal:10 = left:10, right:10)(vertical:10 = top:10, bottom:10)
              contentPadding: EdgeInsets.zero,
              shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
              content: Container(
                width: MediaQuery.of(context).size.width - 20,
                // width = device width minus insetPadding = deviceWidth - 20  (left:10, right:10 = 20)
                height: MediaQuery.of(context).size.height - 20,
                // height = device height minus insetPadding = deviceHeight - 20  (top:10, bottom:10 = 20)
                child: ClipRRect(
                  borderRadius: BorderRadius.circular(10),
                  child: Card(
                    margin: EdgeInsets.zero,
                    color: Colors.amber,
                  ),
                ),
              ),
            ),
          );
        }
      

      【讨论】:

        【解决方案9】:

        使用 Dialog()

        Dialog(
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
          insetPadding: EdgeInsets.all(15),
          child: SingleChildScrollView(
            child: Container(),
            ),
          ),
        );
        

        【讨论】:

        • 最好提供一些关于答案的细节,以供将来在 SO 社区参考。
        【解决方案10】:

        参考此代码。您可以通过设置insetPadding来更改对话框的宽度和高度,因为它采用默认填充,所以我们需要这样更改。

        showDialog(
          context: context,
          builder: (_) =>
           Dialog(
             insetPadding: EdgeInsets.symmetric(horizontal: 2.0, vertical: 2.0),
             backgroundColor: Colors.transparent,
            child: Container(
              width: double.infinity,
              height: MediaQuery.of(context).size.height*0.7 ,
              decoration: BoxDecoration(
                color: Colors.grey[900],
              ),
              child: Column(
                children: [
                  Padding(
                    padding: const EdgeInsets.all(10.0),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.end,
                      children: [
                        GestureDetector(
                          onTap: (){
                            Navigator.pop(context);
                          },
                            child: Icon(Icons.close,color: Colors.grey,)),
                      ],
                    ),
                  ),
                  Text("select your avatar",style: TextStyle(color: white,fontWeight: FontWeight.bold),),
                ],
              ),
            ),
          ),
        );
        

        【讨论】:

          【解决方案11】:

          插入 insetWidth 和 future builder 等对我不起作用 - 只需编辑 content prop 的宽度就可以了。

          showDialog(
              context: context,
              builder: (context) {
                Future.delayed(Duration(seconds: 1000), () {
                  Navigator.of(context).pop(true);
                });
                return AlertDialog(
                  insetPadding: EdgeInsets.all(8.0),
                  title: Text(
                    "Time to go pro!",
                    textAlign: TextAlign.center,
                  ),
                  content: Container(
                    width: MediaQuery.of(context).size.width,
                    child: BuySheet(
                        applePayEnabled: applePayEnabled,
                        googlePayEnabled: googlePayEnabled,
                        applePayMerchantId: applePayMerchantId,
                        squareLocationId: squareLocationId),
                  ),
                );
              });
          

          【讨论】:

          • 太棒了! insetPadding + container's width 制作全角对话框。
          【解决方案12】:

          您好,您实际上可以使用 insetPadding 并在内容中使用包含 SizedBox(width:MediaQuery.of(context).size.width) 的列。唯一的区别是我使用了 AlertDialog。贝娄是它为我工作的方式。您可以通过更改 insetPadding 内的填充来设置对话框宽度。希望我有所帮助:)。

          dialog(){
          TextEditingController controller = TextEditingController();
          
          return showDialog(
            context: context,
            barrierDismissible: true,
            builder: (_) => AlertDialog(
              insetPadding:  EdgeInsets.symmetric(
                  horizontal: MediaQuery.of(context).size.width * 0.08),
              content: SingleChildScrollView(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.start,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    SizedBox(
                      height: 16,
                      width: MediaQuery.of(context).size.width,
                    ),
                    Text(
                      'Hello',
                    ),
                    SizedBox(
                      height: 15,
                    ),
                    Text(
                      'Description',
                    ),
                    TextField(
                      controller: controller,
                      style: TextStyle(
                        color: Colors.black,
                      ),
                    ),
                  ],
                ),
              ),
              actions: [
                FlatButton(
                  child: Text("Close"),
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                ),
              ],
            ),
          );
          

          }

          这就是它的样子 https://i.stack.imgur.com/bvKpP.png

          【讨论】:

            【解决方案13】:
            return Dialog(
                  insetPadding: EdgeInsets.symmetric(
                    horizontal: X,
                  ),
            );
            

            【讨论】:

            • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助,质量更高,更有可能吸引投票。
            【解决方案14】:

             return Dialog(
            
              backgroundColor: Colors.white,
              insetPadding: EdgeInsets.all(10.0),
              child: Container(
               
                width: double.infinity,
            

            在返回 Dialog 的地方使用 insetpadding 并给它一个 double 值,就我而言,我给它一个 10.0 insetPadding: E​​dgeInsets.all(10.0),你可以给它一个自定义高度

            【讨论】:

              【解决方案15】:

              我终于找到了改变 AlertDialog 宽度的方法。 只需用容器包装“内容”,并为其设置宽度。

              return AlertDialog(
              ...
              content: Container(
                 width: MediaQuery.of(context).size.width*0.45,
                 child: ...
              

              AlertDialog with width modified

              【讨论】:

              • 所有其他更复杂或使用其他小部件的解决方案。
              【解决方案16】:

              就我而言,我在对话框中使用 listview,所以我没有使用 ListView 中的收缩包装希望这会对某人有所帮助。

              ListView.builder(
              shrinkWrap : true...
              ...
              };
              

              【讨论】:

                【解决方案17】:

                我找到了最简单的方法......只需添加 insetPadding: EdgeInsets.zero,,它就会扩展到最大尺寸宽度:

                 showDialog(
                          context: context,
                          builder: (BuildContext context) {
                            return AlertDialog(
                              title: Center(child: Text("Send Message", style: TextStyle(
                                  color: Colors.white, fontWeight: FontWeight.bold),)),
                              backgroundColor: Colors.indigo[700],
                              insetPadding: EdgeInsets.zero,
                              content:
                

                【讨论】:

                • 请显示这个工作的截图,因为目前这并没有扩大 AlertDialog 的宽度
                【解决方案18】:

                像这样添加 InsetPadding 属性

                     insetPadding: EdgeInsets.zero
                
                
                
                
                  AlertDialog(
                      title: Center(child: Text("$title")),
                ------------------------->Here we added the property
                      insetPadding: EdgeInsets.zero,
                      titlePadding: EdgeInsets.only(top: 14.0, bottom: 4),
                      content: Container(
                        height: 50,
                        child: TextFormField(
                          controller: find_controller,
                          decoration: InputDecoration(
                            suffixIcon: context.watch<MediaProvider>().isChangeDialog
                                ? IconButton(
                                    onPressed: () {
                                      clearController(find_controller);
                                    },
                                    icon: Icon(Icons.clear))
                                : null,
                            border: OutlineInputBorder(
                                borderSide: BorderSide(color: Colors.deepPurpleAccent)),
                            hintText: 'Id',
                          ),
                          onChanged: (val) {
                            if (val.isNotEmpty)
                              context.read<MediaProvider>().isChangeDialog = true;
                            else
                              context.read<MediaProvider>().isChangeDialog = false;
                          },
                        ),
                      ),
                      actions: [
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            Padding(
                              padding: const EdgeInsets.all(4.0),
                              child: OutlinedButton(
                                  child: Row(
                                    mainAxisAlignment: MainAxisAlignment.center,
                                    children: [
                                      Align(
                                        child: Padding(
                                          padding: const EdgeInsets.symmetric(horizontal: 12.0),
                                          child: Icon(Icons.clear),
                                        ),
                                      ),
                                      Text("Cancel")
                                    ],
                                  ),
                                  onPressed: () {
                                    context.read<MediaProvider>().isChangeDialog = false;
                                    Navigator.of(context).pop();
                                  }),
                            ),
                            Padding(
                              padding: const EdgeInsets.all(4.0),
                              child: ElevatedButton(
                                  onPressed: context.watch<MediaProvider>().isChangeDialog
                                      ? () {
                                          context.read<MediaProvider>().isChangeDialog = false;
                                          okCallback;
                                        }
                                      : null,
                                  child: Row(
                                    mainAxisAlignment: MainAxisAlignment.center,
                                    children: [
                                      Align(
                                        child: Padding(
                                          padding: const EdgeInsets.symmetric(horizontal: 12.0),
                                          child: Icon(Icons.check),
                                        ),
                                      ),
                                      Text("OK")
                                    ],
                                  )),
                            )
                          ],
                        ),
                      ],
                    );
                

                之前

                之后

                【讨论】:

                  【解决方案19】:

                  我正在使用get 包,它很棒。使用它的对话框,很容易调整大小

                  Get.generalDialog(pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation,) {
                        return SimpleDialog(
                          shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(Constants.padding), ),
                          elevation: 0, backgroundColor: Colors.transparent,
                          children: [Center(child: Stack(
                            children: <Widget>[
                              Container(width: Get.width * 0.95,
                                padding: const EdgeInsets.only(left: Constants.padding,top: Constants.avatarRadius
                                    + Constants.padding, right: Constants.padding,bottom: Constants.padding
                                ),
                                margin: const EdgeInsets.only(top: Constants.avatarRadius),
                                decoration: BoxDecoration(
                                  shape: BoxShape.rectangle,
                                  color: Get.theme.scaffoldBackgroundColor,
                                  borderRadius: BorderRadius.circular(Constants.padding),
                                  boxShadow: const [
                                    BoxShadow(color: Colors.black,offset: Offset(0,10), blurRadius: 10 ),
                                  ]
                                ),
                                child: Text('body'),
                              ),
                              Positioned(
                                left: Constants.padding, right: Constants.padding,
                                child: CircleAvatar(
                                  backgroundColor: Colors.blueAccent, radius: Constants.avatarRadius,
                                  child: ClipRRect(
                                    borderRadius: const BorderRadius.all(Radius.circular(Constants.avatarRadius)),
                                    child: Icon(Icons.done, size: 24, color: Colors.white,)
                                  ),
                                ),
                              ),
                              Positioned(
                                left: 0,
                                //right: Constants.padding,
                                child: CircleAvatar(
                                  backgroundColor: Colors.blueAccent, radius: Constants.avatarRadius,
                                  child: ClipRRect(
                                    borderRadius: const BorderRadius.all(Radius.circular(Constants.avatarRadius)),
                                    child: InkWell(child: const Icon(Icons.close, size: 24, color: Colors.white,), onTap: (){Get.back();},)
                                  ),
                                ),
                              ),
                            ],
                          ))],
                        );
                      }, barrierDismissible: true, barrierLabel: '');
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2021-11-02
                    • 2021-08-26
                    • 2021-01-02
                    • 2021-06-12
                    • 2011-03-04
                    • 2013-09-14
                    • 2011-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多