如何在flutter中实现自定义对话框?

问题描述 投票:0回答:12

我是 flutter 新手,需要创建一个图库应用程序,该应用程序需要自定义对话框来显示所选图像。我怎样才能实现它?

flutter flutter-layout
12个回答
98
投票

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

这是一个代码示例:

 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);}

69
投票

屏幕截图(空安全):


代码:

只需调用这个方法:

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,
        ),
      );
    },
  );
}

18
投票

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

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);
                                   */ });
                                  },
                                ))
                          ),
                        ],
                      ))
                    ],
                  )),
            ),
          ),
        );
      }
    }

16
投票

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

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(),
)

13
投票
  1. 警报对话框
  2. 自定义对话框
  3. 全屏对话框

ref:Flutter 警报对话框到自定义对话框 |作者:伊尚·费尔南多 |代码柴 |中等

警报对话框

showDialog(
  context: context,
  builder: (BuildContext context) {
    return AlertDialog(
      title: Text("Alert Dialog"),
      content: Text("Dialog Content"),
      actions: [
        TextButton(
          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),
                )
              ],
            ),
          ),
        );
      });

6
投票

我通常为与应用程序主题匹配的对话框构建一个包装器,并避免太多冗余代码。

占位符对话框

class PlaceholderDialog extends StatelessWidget {
  const PlaceholderDialog({
    this.icon,
    this.title,
    this.message,
    this.actions = const [],
    Key? key,
  }) : super(key: key);

  final Widget? icon;
  final String? title;
  final String? message;
  final List<Widget> actions;

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(20.0),
      ),
      icon: icon,
      title: title == null
          ? null
          : Text(
              title!,
              textAlign: TextAlign.center,
            ),
      titleTextStyle: AppStyle.bodyBlack,
      content: message == null
          ? null
          : Text(
              message!,
              textAlign: TextAlign.center,
            ),
      contentTextStyle: AppStyle.textBlack,
      actionsAlignment: MainAxisAlignment.center,
      actionsOverflowButtonSpacing: 8.0,
      actions: actions,
    );
  }
}

使用方法

    showDialog(
      context: context,
      builder: (ctx) => PlaceholderDialog(
        icon: Icon(
          Icons.add_circle,
          color: Colors.teal,
          size: 80.0,
        ),
        title: 'Save Failed',
        message: 'An error occurred when attempt to save the message',
        actions: [
          TextButton(
            onPressed: () => Navigator.of(ctx).pop(),
            child: Text('!Got It'),
          ),
        ],
      ),
    );

结果


4
投票

一般例

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')),
        ),
      ],
    );
  }

3
投票

Flutter 中的自定义警报对话框

  void openAlert() {
    dialog = Dialog(
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.0)),
      //this right here
      child: Container(
        height: 350.0,
        width: double.infinity,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            ClipRRect(
              child: Image.asset(
                "assets/images/water1.jpg",
                width: double.infinity,
                height: 180,
                fit: BoxFit.cover,
              ),
              borderRadius: BorderRadius.only(
                  topLeft: Radius.circular(16), topRight: Radius.circular(16)),
            ),
            Container(
              margin: EdgeInsets.only(top: 16),
              decoration: boxDecorationStylealert,
              width: 200,
              padding: EdgeInsets.symmetric(horizontal: 8),
              height: 50,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  GestureDetector(
                      onTap: () {
                        showToastMessage("-");
                      },
                      child:Image.asset("assets/images/subtraction.png",width: 30,height: 30,)),
                  Text(
                    "1",
                    style: TextStyle(
                        fontSize: 26,
                        fontWeight: FontWeight.bold,
                        color: black_color),
                  ),
                  GestureDetector(
                      onTap: () {
                        showToastMessage("+");
                      },
                      child:Image.asset("assets/images/add.png",width: 30,height: 30,)),
                ],
              ),
            ),
            Expanded(child: Container()),
            Row(
              children: [
                Expanded(
                  child: Padding(
                    padding: EdgeInsets.only(left: 12, right: 6),
                    child: MaterialButton(
                      onPressed: cancelClick,
                      color: green_color,
                      child: Text(
                        "CANCEL",
                        style: TextStyle(fontSize: 12, color: white_color),
                      ),
                      shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(4)),
                    ),
                  ),
                ),
                Expanded(
                  child: Padding(
                    padding: EdgeInsets.only(left: 6, right: 12),
                    child: MaterialButton(
                      onPressed: okClick,
                      color: green_color,
                      child: Text(
                        "OK",
                        style: TextStyle(fontSize: 12, color: white_color),
                      ),
                      shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(4)),
                    ),
                  ),
                )
              ],
            )
          ],
        ),
      ),
    );
    showDialog(
        context: context, builder: (BuildContext context) => dialog);
  }

2
投票

您现在可以使用 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))),}),

1
投票

我的案例有一个有效的解决方案:

  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();
          },
        ),
      ],
    );
  },
);
}

1
投票

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

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.   

-1
投票

这个答案更多的是问题的标题而不是细节。 IE。 “如何在 flutter 中构建自定义对话框?”

要点是创建返回

CustomDialog
AlertDialog
类。这样代码就更干净、更具可读性。另外,
CustomDialog
扩展了
ConsumerWidget
,因此,提供者可以用来获取数据,而不需要将数据作为参数传递给构造函数:

自定义_dialog.dart

 class CustomDialog extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final repeatSettings = ref.watch(repeatSettingsProvider);
    int time = repeatSettings.grammaryMinAutoLearningTimeMin!;
    var primaryColor = Theme.of(context).colorScheme.primary;
    var secondaryColor = Theme.of(context).colorScheme.secondary;
    var tertiaryColor = Theme.of(context).colorScheme.tertiary;
    return AlertDialog(
      //title: const Text('Засчитать урок?'),

      content: SizedBox(
        height: 100,   //!! applied to content area
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            Text(
              'Вы занимались меньше $time минут',
            ),
            SizedBox(
              height: 30, width: 300,
            ),
            Text('Засчитать урок?',
                style: TextStyle(color: primaryColor, fontSize: 18))
          ],
        ),
      ),
      actions: [
        XFlatButton(
          text: 'Да',
          width: 50,
          height: 25,
          onPressed: () {
            Navigator.of(context).pop();
          },
          bgColor: primaryColor,
        ),
        XFlatButton(
          text: 'Нет',
          width: 55,
          height: 25,
          onPressed: () {
            Navigator.of(context).pop();
          },
          bgColor: secondaryColor,
        ),
         XFlatButton(
          text: 'Отмена',
          width: 90,
          height: 25,
          onPressed: () {
            Navigator.of(context).pop();
          },
          bgColor: tertiaryColor,
        ),
        
      ],
    );
  }
}

这就是它的样子:

注意:

SizedBox
height
适用于内容区域而不是整个小部件。

称呼它:

onPressed: () async {
             
              return _dialogBuilder(context);
            },
...



Future<void> _dialogBuilder(BuildContext context) {
    return showDialog<void>(
      context: context,
      builder: (BuildContext context) {
        return CustomDialog();
      },
    );
  }

如果您喜欢 XFlatButton(否则将其替换为常规 TextButton):

class XFlatButton extends StatelessWidget {
  final String text;
  final void Function()? onPressed;
  final double width;
  final double height;
  final IconData? iconData;
  final Color bgColor;
  final Color iconColor;
  final TextStyle textStyle;

  const XFlatButton(
      {required this.text,
      this.onPressed,
      this.width = 200,
      this.height = 40,
      super.key,
      this.iconData,
      this.bgColor = Colors.blue,
      this.iconColor = Colors.white,
      this.textStyle = const TextStyle(color: Colors.white)});
  @override
  Widget build(BuildContext context) {
    final flatButtonStyle = TextButton.styleFrom(
        padding: EdgeInsets.symmetric(horizontal: 10.0),
        shape: const RoundedRectangleBorder(
          borderRadius: BorderRadius.all(Radius.circular(20.0)),
        ),
        //backgroundColor: bgColor,
        backgroundColor: onPressed == null
            ? Theme.of(context).colorScheme.primaryContainer
            : bgColor);
    return SizedBox(
      width: width,
      height: height,
      child: TextButton(
          onPressed: onPressed,
          style: flatButtonStyle,
          //child: Text(text),
          child: iconData == null
              ? Text(
                  text,
                  style: textStyle,
                )
              : Row(mainAxisAlignment: MainAxisAlignment.center, children: [
                  Icon(
                    iconData,
                    color: iconColor,
                  ),
                  SizedBox(
                    width: 10,
                  ),
                  Text(
                    text,
                    style: textStyle,
                  ),
                ])),
    );
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.