【问题标题】:How to position close button in a Popup in Flutter?如何在 Flutter 的弹出窗口中定位关闭按钮?
【发布时间】:2025-12-11 23:20:04
【问题描述】:

我有一个如下所示的弹出窗口。我试图在弹出窗口的右上角放置一个关闭按钮,但那里似乎有一些我无法摆脱的额外空间。

我也面临一个错误,当我按下 OKAY 按钮时,即使我为它提供了 Navigator.pop(context),弹出窗口也不会被关闭。

这是我的代码:

class Popup {
  final String title;
  final String message;
  final String rightButton;
  final VoidCallback onTapRightButton;
  final String leftButton;
  final VoidCallback onTapLeftButton;
...

 show(BuildContext context) {
    return showDialog(
      context: context,
      barrierDismissible: false,
      builder: (BuildContext context) {
        return _PopupCall(
            title: title,
            message: message,
            leftButton: leftButton ?? 'null',
            rightButton: rightButton,
            onTapLeftButton: onTapLeftButton,
            onTapRightButton: onTapRightButton);
      },
    );
  }
...

       @override
          Widget build(BuildContext context) {
            return ScaleTransition(
              scale: scaleAnimation,
              child: AlertDialog(
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(24),
                  ),
                ),
                title: Wrap(
                  children: <Widget>[
                    Column(
                      crossAxisAlignment: CrossAxisAlignment.stretch,
                      children: <Widget>[
                        Align(
                          alignment: Alignment.topRight,
                          child: IconButton(
                            icon: Icon(
                              Icons.close,
                              color: Colors.red,
                              size: 25,
                            ),
                            onPressed: () {
                              Navigator.pop(context);
                            },
                          ),
                        ),
                        Center(
                          child: Text(widget.title,
                              style: TextStyle(
                                fontFamily: 'TTNorms',
                                fontWeight: FontWeight.bold,
                                wordSpacing: 0,
                                letterSpacing: 0,
                                fontSize: 25,
                                color: Colors.yellow,
                              )),
                        ),
                        const SizedBox(height: 15.0),
                        Text(widget.message,
                            textAlign: TextAlign.center,
                            style: TextStyle(
                              fontFamily: 'TTNorms',
                              fontWeight: FontWeight.w400,
                              wordSpacing: 0,
                              letterSpacing: 0,
                              fontSize: 15,
                              color: Colors.yellow,
                            )),
                        const SizedBox(height: 16.0),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: <Widget>[
                            Visibility(
                              visible: widget.leftButton != 'null',
                              child: Padding(
                                padding: const EdgeInsets.only(bottom: 10.0),
                                child: Center(
                                  child: GestureDetector(
                                    onTap: () {
                                      if (widget.leftButton != 'null') {
                                        widget
                                            .onTapLeftButton(); //function to be performed onTap
                                      }
                                      Navigator.pop(context);
                                    },
                                    child: Container(
                                      height: 40,
                                      width: 80,
                                      decoration: BoxDecoration(
                                          border: Border.all(
                                              color: Colors.yellow, width: 2.0),
                                          borderRadius: BorderRadius.all(
                                            Radius.circular(25),
                                          ),
                                          color: Colors.blue),
                                      child: Center(
                                        child: Text('Okay',
                                            style: TextStyle(
                                              fontFamily: 'TTNorms',
                                              fontWeight: FontWeight.bold,
                                              wordSpacing: 0,
                                              letterSpacing: 0,
                                              fontSize: 15,
                                              color: Colors.yellow,
                                            )),
                                      ),
                                    ),
                                  ),
                                ),
                              ),
                            ),
                            Padding(
                              padding: EdgeInsets.only(
                                bottom: 10.0,
                                left: 10,
                              ),
                              child: Center(
                                child: GestureDetector(
                                  onTap: () {
                                    widget
                                        .onTapRightButton(); //function to be performed onTap
                                    Navigator.pop(context);
                                  },
                                  child: Container(
                                    height: 40,
                                    width: 80,
                                    decoration: BoxDecoration(
                                      borderRadius: BorderRadius.all(
                                        Radius.circular(15),
                                      ),
                                      gradient: kGradientBackground,
                                    ),
                                    child: Center(
                                      child: Text(widget.rightButton.toUpperCase(),
                                          style: TextStyle(
                                            fontFamily: 'TTNorms',
                                            fontWeight: FontWeight.bold,
                                            wordSpacing: 0,
                                            letterSpacing: 0,
                                            fontSize: 15,
                                            color: Colors.blue,
                                          )),
                                    ),
                                  ),
                                ),
                              ),
                            ),
                          ],
                        ),
                      ],
                    ),
                  ],
                ),
              ),
            );
          }

这是弹出窗口的样子:

这就是我调用弹出窗口的方式:

Popup(
        title: 'Oops!',
        message:
            "Looks like there has been a mistake please check later!",
        rightButton: 'OK',
        onTapLeftButton: () {},
        onTapRightButton: () {},
      ).show(context);

【问题讨论】:

    标签: flutter user-interface dart


    【解决方案1】:

    如果你看一下 Flutter Inspector ,你就会明白你的 Popup Dialog 的结构:

    关闭图标的位置由深蓝色的AlertDialogtitlePadding 和浅蓝色的IconButtonpadding 定义。如果您将titlePadding 设置为零,您可能拥有您想要的收盘图标位置:

    但是,现在,您的 AlertDialog 的内容太靠近对话框框架的边框了。我建议将 Dialog 的内容移动到 content 字段,而不是将所有内容都放在 title 中:

    您可以更进一步,将操作按钮移至AlertDialogactions 字段。

    完整源代码:

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(
        MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'Flutter Demo',
          home: HomePage(),
        ),
      );
    }
    
    class HomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: ElevatedButton(
              onPressed: () => Popup(
                title: 'Oops!',
                message: "Looks like there has been a mistake please check later!",
                leftButton: 'Cancel',
                rightButton: 'OK',
                onTapLeftButton: () {},
                onTapRightButton: () {},
              ).show(context),
              child: Text('SHOW POPUP'),
            ),
          ),
        );
      }
    }
    
    class Popup {
      final String title;
      final String message;
      final String rightButton;
      final VoidCallback onTapRightButton;
      final String leftButton;
      final VoidCallback onTapLeftButton;
    
      Popup({
        this.title,
        this.message,
        this.rightButton,
        this.onTapRightButton,
        this.leftButton,
        this.onTapLeftButton,
      });
    
      show(BuildContext context) {
        return showDialog(
          context: context,
          barrierDismissible: false,
          builder: (BuildContext context) {
            return _PopupCall(
                title: title,
                message: message,
                leftButton: leftButton,
                rightButton: rightButton,
                onTapLeftButton: onTapLeftButton,
                onTapRightButton: onTapRightButton);
          },
        );
      }
    }
    
    class _PopupCall extends StatefulWidget {
      final String title;
      final String message;
      final String rightButton;
      final VoidCallback onTapRightButton;
      final String leftButton;
      final VoidCallback onTapLeftButton;
    
      const _PopupCall(
          {Key key,
          this.title,
          this.message,
          this.rightButton,
          this.onTapRightButton,
          this.leftButton,
          this.onTapLeftButton})
          : super(key: key);
      @override
      _PopupCallState createState() => _PopupCallState();
    }
    
    class _PopupCallState extends State<_PopupCall> {
      @override
      Widget build(BuildContext context) {
        return AlertDialog(
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.all(
              Radius.circular(24),
            ),
          ),
          backgroundColor: Colors.black87,
          titlePadding: EdgeInsets.all(0),
          title: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              Align(
                alignment: Alignment.topRight,
                child: IconButton(
                  icon: Icon(
                    Icons.close,
                    color: Colors.red,
                    size: 25,
                  ),
                  onPressed: () {
                    Navigator.pop(context);
                  },
                ),
              ),
              Center(
                child: Text(widget.title,
                    style: TextStyle(
                      fontFamily: 'TTNorms',
                      fontWeight: FontWeight.bold,
                      wordSpacing: 0,
                      letterSpacing: 0,
                      fontSize: 25,
                      color: Colors.yellow,
                    )),
              ),
            ],
          ),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Text(
                widget.message,
                textAlign: TextAlign.center,
                style: TextStyle(
                  fontFamily: 'TTNorms',
                  fontWeight: FontWeight.w400,
                  wordSpacing: 0,
                  letterSpacing: 0,
                  fontSize: 15,
                  color: Colors.yellow,
                ),
              ),
            ],
          ),
          actions: [
            if (widget.leftButton != null)
              Padding(
                padding: const EdgeInsets.only(bottom: 10.0),
                child: Center(
                  child: GestureDetector(
                    onTap: () {
                      widget.onTapLeftButton?.call();
                      Navigator.pop(context);
                    },
                    child: Container(
                      height: 40,
                      width: 80,
                      decoration: BoxDecoration(
                        border: Border.all(color: Colors.yellow, width: 2.0),
                        borderRadius: BorderRadius.all(
                          Radius.circular(25),
                        ),
                        color: Colors.blue,
                      ),
                      child: Center(
                        child: Text(
                          'Okay',
                          style: TextStyle(
                            fontFamily: 'TTNorms',
                            fontWeight: FontWeight.bold,
                            wordSpacing: 0,
                            letterSpacing: 0,
                            fontSize: 15,
                            color: Colors.yellow,
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            Padding(
              padding: EdgeInsets.only(
                bottom: 10.0,
                left: 10,
              ),
              child: Center(
                child: GestureDetector(
                  onTap: () {
                    widget.onTapRightButton?.call();
                    Navigator.pop(context);
                  },
                  child: Container(
                    height: 40,
                    width: 80,
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.all(
                        Radius.circular(15),
                      ),
                    ),
                    child: Center(
                      child: Text(
                        widget.rightButton.toUpperCase(),
                        style: TextStyle(
                          fontFamily: 'TTNorms',
                          fontWeight: FontWeight.bold,
                          wordSpacing: 0,
                          letterSpacing: 0,
                          fontSize: 15,
                          color: Colors.blue,
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            )
          ],
        );
      }
    }
    

    【讨论】:

    • 注意,如果不关闭对话框,我无法重现该问题。
    • 帮了大忙!谢谢!
    【解决方案2】:

    修改您的类以从 Stateful Widget 中检索函数。显示弹出窗口时,将您的 Navigator.pop(context) 操作传递给该函数。在 popup 类中,使用传递的函数关闭自身。

    【讨论】:

      最近更新 更多