【问题标题】:How to implement a Custom dialog box in flutter?Flutter中如何实现自定义对话框?
【发布时间】:2019-03-31 19:46:59
【问题描述】:

我是 Flutter 新手,需要创建一个图库应用,该应用需要自定义对话框来显示所选图像。我该如何实现?

【问题讨论】:

标签: flutter flutter-layout


【解决方案1】:

一个通用的例子

showDialog(context: context,builder: (context) => _onTapImage(context)); // Call the Dialog.

_onTapImage(BuildContext context) {
    return Stack(
      alignment: Alignment.center,
      children: <Widget>[
        Image.network('https://via.placeholder.com/150',fit: BoxFit.contain,), // Show your Image
        Align(
          alignment: Alignment.topRight,
          child: RaisedButton.icon(
              color: Theme.of(context).accentColor,
              textColor: Colors.white,
              onPressed: () => Navigator.pop(context),
              icon: Icon(
                Icons.close,
                color: Colors.white,
              ),
              label: Text('Close')),
        ),
      ],
    );
  }

【讨论】:

    【解决方案2】:

    使用 Dialog 类,它是 Flutter 中 AlertDialog 类的父类。对话框小部件有一个参数“shape”,您可以使用它来塑造对话框的边缘。

    这是一个代码示例:

     Dialog errorDialog = Dialog(
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)), //this right here
      child: Container(
        height: 300.0,
        width: 300.0,
       
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding:  EdgeInsets.all(15.0),
              child: Text('Cool', style: TextStyle(color: Colors.red),),
            ),
            Padding(
              padding: EdgeInsets.all(15.0),
              child: Text('Awesome', style: TextStyle(color: Colors.red),),
            ),
            Padding(padding: EdgeInsets.only(top: 50.0)),
            TextButton(onPressed: () {
              Navigator.of(context).pop();
            },
                child: Text('Got It!', style: TextStyle(color: Colors.purple, fontSize: 18.0),))
          ],
        ),
      ),
    );
    showDialog(context: context, builder: (BuildContext context) => errorDialog);}
    

    【讨论】:

    • 假设我们有自定义对话框类,我们在另一个 Statefulwidget onTap 中使用它: () { showDialog( context: context, builder: (context) { return CustomDialog(); }); },我们是否必须将上下文传递给 customDialog。 (我认为如果对话框对该 statefulwidget 进行一些更改,这是否会使洞小部件再次重建)
    【解决方案3】:

    在按钮上单击显示对话框为 -

    showDialog(
            context: context,
            builder: (_) => LogoutOverlay(),
          );
    

    带有两个按钮的对话框设计 -

    class LogoutOverlay extends StatefulWidget {
          @override
          State<StatefulWidget> createState() => LogoutOverlayState();
        }
    
        class LogoutOverlayState extends State<LogoutOverlay>
            with SingleTickerProviderStateMixin {
          AnimationController controller;
          Animation<double> scaleAnimation;
    
          @override
          void initState() {
            super.initState();
    
            controller =
                AnimationController(vsync: this, duration: Duration(milliseconds: 450));
            scaleAnimation =
                CurvedAnimation(parent: controller, curve: Curves.elasticInOut);
    
            controller.addListener(() {
              setState(() {});
            });
    
            controller.forward();
          }
    
          @override
          Widget build(BuildContext context) {
            return Center(
              child: Material(
                color: Colors.transparent,
                child: ScaleTransition(
                  scale: scaleAnimation,
                  child: Container(
                    margin: EdgeInsets.all(20.0),
                      padding: EdgeInsets.all(15.0),
                      height: 180.0,
    
                      decoration: ShapeDecoration(
                          color: Color.fromRGBO(41, 167, 77, 10),
                          shape: RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(15.0))),
                      child: Column(
                        children: <Widget>[
                          Expanded(
                              child: Padding(
                            padding: const EdgeInsets.only(
                                top: 30.0, left: 20.0, right: 20.0),
                            child: Text(
                              "Are you sure, you want to logout?",
                              style: TextStyle(color: Colors.white, fontSize: 16.0),
                            ),
                          )),
                          Expanded(
                              child: Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: <Widget>[
                              Padding(
                                padding: const EdgeInsets.all(10.0),
                                child: ButtonTheme(
                                    height: 35.0,
                                    minWidth: 110.0,
                                    child: RaisedButton(
                                      color: Colors.white,
                                      shape: RoundedRectangleBorder(
                                          borderRadius: BorderRadius.circular(5.0)),
                                      splashColor: Colors.white.withAlpha(40),
                                      child: Text(
                                        'Logout',
                                        textAlign: TextAlign.center,
                                        style: TextStyle(
                                            color: Colors.green,
                                            fontWeight: FontWeight.bold,
                                            fontSize: 13.0),
                                      ),
                                      onPressed: () {
                                        setState(() {
                                          Route route = MaterialPageRoute(
                                              builder: (context) => LoginScreen());
                                          Navigator.pushReplacement(context, route);
                                        });
                                      },
                                    )),
                              ),
                              Padding(
                                padding: const EdgeInsets.only(
                                    left: 20.0, right: 10.0, top: 10.0, bottom: 10.0),
                                child:  ButtonTheme(
                                    height: 35.0,
                                    minWidth: 110.0,
                                    child: RaisedButton(
                                      color: Colors.white,
                                      shape: RoundedRectangleBorder(
                                          borderRadius: BorderRadius.circular(5.0)),
                                      splashColor: Colors.white.withAlpha(40),
                                      child: Text(
                                        'Cancel',
                                        textAlign: TextAlign.center,
                                        style: TextStyle(
                                            color: Colors.green,
                                            fontWeight: FontWeight.bold,
                                            fontSize: 13.0),
                                      ),
                                      onPressed: () {
                                        setState(() {
                                          /* Route route = MaterialPageRoute(
                                              builder: (context) => LoginScreen());
                                          Navigator.pushReplacement(context, route);
                                       */ });
                                      },
                                    ))
                              ),
                            ],
                          ))
                        ],
                      )),
                ),
              ),
            );
          }
        }
    

    【讨论】:

    • 我收到错误“没有为类 LogoutOverlayState”定义方法 'LoginScreen'。...尝试将名称更正为现有方法的名称,或定义一个名为“LoginScreen”的方法。 "
    • LoginScreen 是一个页面名称,它将在点击“注销”时重定向。
    【解决方案4】:

    你只需将这个类放到你的项目中并调用它的方法来显示对话框。
    使用这个类你不需要到处写对话框代码

    class DialogUtils {
      static DialogUtils _instance = new DialogUtils.internal();
    
      DialogUtils.internal();
    
      factory DialogUtils() => _instance;
    
      static void showCustomDialog(BuildContext context,
          {@required String title, 
          String okBtnText = "Ok",
          String cancelBtnText = "Cancel",
          @required Function okBtnFunction}) {
        showDialog(
            context: context,
            builder: (_) {
              return AlertDialog(
                title: Text(title),
                content: /* Here add your custom widget  */,
                actions: <Widget>[
                  FlatButton(
                    child: Text(okBtnText),
                    onPressed: okBtnFunction,
                  ),
                  FlatButton(
                      child: Text(cancelBtnText),
                      onPressed: () => Navigator.pop(context))
                ],
              );
            });
      }
     }
    

    你可以像这样调用这个方法:

    GestureDetector(
          onTap: () =>
                  DialogUtils.showCustomDialog(context,
              title: "Gallary",
              okBtnText: "Save",
              cancelBtnText: "Cancel",
              okBtnFunction: () => /* call method in which you have write your logic and save process  */),
          child: Container(),
    )
    

    【讨论】:

    • 此解决方案完美运行。您能否详细说明为什么使用.internal?我想了解内部和工厂语义的背景
    • 仅用于创建单例类@JulianOtto
    • 为什么还需要持久化这个实例?那是 100% 无状态对话框,不需要保存它的实例,您可以在这里使用简单的静态方法
    • 我尝试了这个解决方案,但我得到了这个错误Error: The argument type 'Function' can't be assigned to the parameter type 'void Function()?'.
    【解决方案5】:

    屏幕截图(Null Safe):


    代码:

    只要调用这个方法:

    void showCustomDialog(BuildContext context) {
      showGeneralDialog(
        context: context,
        barrierLabel: "Barrier",
        barrierDismissible: true,
        barrierColor: Colors.black.withOpacity(0.5),
        transitionDuration: Duration(milliseconds: 700),
        pageBuilder: (_, __, ___) {
          return Center(
            child: Container(
              height: 240,
              child: SizedBox.expand(child: FlutterLogo()),
              margin: EdgeInsets.symmetric(horizontal: 20),
              decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(40)),
            ),
          );
        },
        transitionBuilder: (_, anim, __, child) {
          Tween<Offset> tween;
          if (anim.status == AnimationStatus.reverse) {
            tween = Tween(begin: Offset(-1, 0), end: Offset.zero);
          } else {
            tween = Tween(begin: Offset(1, 0), end: Offset.zero);
          }
      
          return SlideTransition(
            position: tween.animate(anim),
            child: FadeTransition(
              opacity: anim,
              child: child,
            ),
          );
        },
      );
    }
    

    【讨论】:

      【解决方案6】:

      您现在可以使用 AlertDialog 并在内容中构建您的小部件。

      showDialog(
      context: context,
      builder: (BuildContext context) {
         return AlertDialog(
           shape: RoundedRectangleBorder(
           borderRadius: BorderRadius.all(Radius.circular(20.0))),
           backgroundColor: Colors.green,
           content: Container(
               height:200,
               width:200,
               decoration: BoxDecoration(
                          image: DecorationImage(
                                image: FileImage(filepath),
                                fit: BoxFit.cover))),}),
      

      【讨论】:

        【解决方案7】:
        1. 警报对话框
        2. 自定义对话框
        3. 全屏对话框

        参考:Flutter Alert Dialog to Custom Dialog | by Ishan Fernando | CodeChai | Medium

        警报对话框

        showDialog(
                      context: context,
                      builder: (BuildContext context){
                          return AlertDialog(
                            title: Text("Alert Dialog"),
                            content: Text("Dialog Content"),
                          );
                      },
                      actions:[
                              FlatButton(
                                child: Text("Close"),
                                onPressed: (){
                                  Navigator.of(context).pop();
                                },
                              )
                            ],
                    );
        

        自定义对话框

        showDialog(
                context: context,
                builder: (BuildContext context) {
                  return Dialog(
                    shape: RoundedRectangleBorder(
                        borderRadius:
                            BorderRadius.circular(20.0)), //this right here
                    child: Container(
                      height: 200,
                      child: Padding(
                        padding: const EdgeInsets.all(12.0),
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            TextField(
                              decoration: InputDecoration(
                                  border: InputBorder.none,
                                  hintText: 'What do you want to remember?'),
                            ),
                            SizedBox(
                              width: 320.0,
                              child: RaisedButton(
                                onPressed: () {},
                                child: Text(
                                  "Save",
                                  style: TextStyle(color: Colors.white),
                                ),
                                color: const Color(0xFF1BC0C5),
                              ),
                            )
                          ],
                        ),
                      ),
                    ),
                  );
                });
        

        全屏对话框

        showGeneralDialog(
              context: context,
              barrierDismissible: true,
              barrierLabel: MaterialLocalizations.of(context)
                  .modalBarrierDismissLabel,
              barrierColor: Colors.black45,
              transitionDuration: const Duration(milliseconds: 200),
              pageBuilder: (BuildContext buildContext,
                  Animation animation,
                  Animation secondaryAnimation) {
                return Center(
                  child: Container(
                    width: MediaQuery.of(context).size.width - 10,
                    height: MediaQuery.of(context).size.height -  80,
                    padding: EdgeInsets.all(20),
                    color: Colors.white,
                    child: Column(
                      children: [
                        RaisedButton(
                          onPressed: () {
                            Navigator.of(context).pop();
                          },
                          child: Text(
                            "Save",
                            style: TextStyle(color: Colors.white),
                          ),
                          color: const Color(0xFF1BC0C5),
                        )
                      ],
                    ),
                  ),
                );
              });
        

        【讨论】:

          【解决方案8】:

          在我的情况下有一个可行的解决方案:

            Future<void> _showMyDialog() async {
            return showDialog<void>(
            context: context,
            barrierDismissible: false, // user must tap button!
            builder: (BuildContext context) {
              return AlertDialog(
                title: Text('AlertDialog Title'),
                content: SingleChildScrollView(
                  child: Column(
                    children: <Widget>[
                      Text('This is a demo alert dialog.'),
                      Text('Would you like to confirm this message?'),
                    ],
                  ),
                ),
                actions: <Widget>[
                  TextButton(
                    child: Text('Confirm'),
                    onPressed: () {
                      print('Confirmed');
                      Navigator.of(context).pop();
                    },
                  ),
                  TextButton(
                    child: Text('Cancel'),
                    onPressed: () {
                      Navigator.of(context).pop();
                    },
                  ),
                ],
              );
            },
          );
          }
          

          【讨论】:

            【解决方案9】:

            希望这会有所帮助: 我在一个单独的类中创建了静态函数:

            import 'package:flutter/material.dart';
            import 'package:flutter_application_1/TGColors.dart';
            
            class TGDialog 
            {
              static doNothing() {  }  // stub needed for Function     parameters
            
            /// Returns an AlertDialog with most optional parameters 
            
             static AlertDialog dlg(  BuildContext context,
                                 { String      txtTitle      = 'WHAT? no title?'  ,
                                   String      txtMsg        = 'WHAT? no content?',
                                   String      txtBtn1       = 'CANCEL'           ,
                                   String      txtBtn2       = 'OK'               , 
                                   Function    funcBtn1      = doNothing          ,
                                   Function    funcBtn2      = doNothing          ,
                                   Color       colBackground = TGColors.Orange    ,
                                   Color       colText       = TGColors.Indigo     } ) 
             {
              return
                AlertDialog(
                    backgroundColor : colBackground,
                    title           : Text(txtTitle),
                    content         : Text(txtMsg),
                    
                    actions : <Widget>
                    [
                      TextButton(
                        onPressed : () => { funcBtn1(), Navigator.pop(context,'Cancel')},
                        child     : Text(txtBtn1, style: TextStyle(color: colText)),
                      ),
            
                      TextButton(
                        onPressed :() => { funcBtn2(),Navigator.pop(context)  },
                        child     : Text(txtBtn2, style: TextStyle(color: colText)),
                      ),
                    ],
                );
              }
            } 
            

            一个例子:

            Positioned( bottom: 1, left: (screenW / 5.6), 
                        child    : FloatingActionButton(
                        heroTag  : 'clear',
            
                        onPressed :() => showDialog<String>
                        (
                          context : context,
                         
                          builder : (BuildContext context) => 
                            ///////////////////////////////////////////////////////
                            TGDialog.dlg( context, 
                                          txtTitle : 'Clear Order?',
                                          txtMsg   : 'This resets all item counts' , 
                                          funcBtn2 : resetOrder) 
                            ///////////////////////////////////////////////////////
                        ),
                       
                        child     : const Text('clear\nall', textAlign: TextAlign.center),
                        shape     : RoundedRectangleBorder(
                                      borderRadius: BorderRadius.circular(40),
                                    ),
                      ),
                    ), 
            

            等等。 顺便说一句:我喜欢 CSS webcolors,所以我在一个单独的类中定义了它们 像这样:

            import 'dart:ui';
            /// Contains mainly web colors  (based on CSS)
            /// 
            /// Usage e.g:  ... = TGcolors.CornFlowerBlue
            class TGColors
            {
              static const  PrimaryColor =  Color(0xFF808080);
              static const  AliceBlue =  Color(0xFFF0F8FF);
              static const  AntiqueWhite = Color(0xFFFAEBD7);
              static const  Aqua = Color(0xFF00FFFF);
              static const  Aquamarine = Color(0xFF7FFFD4);  
              // etc.   
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2019-02-23
              • 2014-07-29
              • 1970-01-01
              • 2023-01-10
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多