Ajnas Askar
Ajnas Askar

Reputation: 1093

How to implement a Custom dialog box in flutter?

I'm new to flutter and need to create a gallery app that needs a custom dialog box to show the selected image. How can I implement that?

Upvotes: 62

Views: 163434

Answers (12)

Yuriy N.
Yuriy N.

Reputation: 6067

This answer is more to the title of the questions than the details. I.e. "How to build a custom dialog in flutter?"

The main point is to create CustomDialog class that returns AlertDialog. This way code is cleaner and more readable. Also, CustomDialog extends ConsumerWidget, hence, providers can be used to get data, and no need to pass data as arguments to constructor:

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

This is what it looks like:

enter image description here

Note: SizedBox height applied to the content area and not the whole widget.

Call it:

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



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

And if you like an XFlatButton (otherwise replace it with regular 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,
                  ),
                ])),
    );
  }
}

Upvotes: -2

Safal Bhatia
Safal Bhatia

Reputation: 405

enter image description hereCustom Alert Dialog in 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);
  }

Upvotes: 3

Ahmed M. Hassan
Ahmed M. Hassan

Reputation: 1286

I usually build a wrapper for the dialog that matches the app theme and avoids much redundant code.

PlaceholderDialog

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

Usage

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

Result

enter image description here

Upvotes: 7

iHTCboy
iHTCboy

Reputation: 2797

  1. Alert Dialog
  2. Custom Dialog
  3. Full-Screen Dialog

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

Alert Dialog

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

Custom Dialog

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

Full-Screen Dialog

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

Upvotes: 14

CopsOnRoad
CopsOnRoad

Reputation: 267384

Screenshot (Null Safe):

enter image description here


Code:

Just call this method:

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

Upvotes: 72

Ted van Gaalen
Ted van Gaalen

Reputation: 1169

Hope this is helpful: I've made static function in a separate class:

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

An example:

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

etc. Btw: I like CSS webcolors so I defined them in a separate class like so:

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.   

Upvotes: 1

Pratik Jain
Pratik Jain

Reputation: 1156

Use Dialog class which is a parent class to AlertDialog class in Flutter. Dialog widget has a argument , "shape" which you can use to shape the Edges of the Dialog box.

Here is a code sample:

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

Upvotes: 100

Almett
Almett

Reputation: 906

There's a working solution in my case:

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

Upvotes: 1

Ahmed Raza
Ahmed Raza

Reputation: 540

You can now use AlertDialog and in content build your widget.

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

Upvotes: 2

Sanjayrajsinh
Sanjayrajsinh

Reputation: 17078

You just put this class in your project and call its method for showing dialog.
Using this class you don't need to write dialog code everywhere

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

You can call this method like :

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

Upvotes: 16

Nikhat Shaikh
Nikhat Shaikh

Reputation: 3685

On a button click show dialog as -

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

Dialog design with two buttons -

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

Upvotes: 19

anmol.majhail
anmol.majhail

Reputation: 51176

An General E.g

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

Upvotes: 4

Related Questions