How to make an AlertDialog in Flutter?
Asked Answered
T

18

200

I am learning to build apps in Flutter. Now I have come to alert dialogs. I have done them before in Android and iOS, but how do I make an alert in Flutter?

Here are some related SO questions:

I'd like to make a more general canonical Q&A so my answer is below.

Toiletry answered 19/12, 2018 at 3:10 Comment(2)
The Best way to use alert dialog is to create a separate class for the alert dialog and use it in the entire project. Refer this : arkapp.medium.com/…Vesicate
Here's a customizable dialog: https://mcmap.net/q/76969/-how-to-show-alertdialog-when-button-is-pressedPastelist
T
357

One Button

showAlertDialog(BuildContext context) {

  // set up the button
  Widget okButton = TextButton(
    child: Text("OK"),
    onPressed: () { },
  );

  // set up the AlertDialog
  AlertDialog alert = AlertDialog(
    title: Text("My title"),
    content: Text("This is my message."),
    actions: [
      okButton,
    ],
  );

  // show the dialog
  showDialog(
    context: context,
    builder: (BuildContext context) {
      return alert;
    },
  );
}

Two Buttons

showAlertDialog(BuildContext context) {

  // set up the buttons
  Widget cancelButton = TextButton(
    child: Text("Cancel"),
    onPressed:  () {},
  );
  Widget continueButton = TextButton(
    child: Text("Continue"),
    onPressed:  () {},
  );

  // set up the AlertDialog
  AlertDialog alert = AlertDialog(
    title: Text("AlertDialog"),
    content: Text("Would you like to continue learning how to use Flutter alerts?"),
    actions: [
      cancelButton,
      continueButton,
    ],
  );

  // show the dialog
  showDialog(
    context: context,
    builder: (BuildContext context) {
      return alert;
    },
  );
}

Three Buttons

showAlertDialog(BuildContext context) {

  // set up the buttons
  Widget remindButton = TextButton(
    child: Text("Remind me later"),
    onPressed:  () {},
  );
  Widget cancelButton = TextButton(
    child: Text("Cancel"),
    onPressed:  () {},
  );
  Widget launchButton = TextButton(
    child: Text("Launch missile"),
    onPressed:  () {},
  );

  // set up the AlertDialog
  AlertDialog alert = AlertDialog(
    title: Text("Notice"),
    content: Text("Launching this missile will destroy the entire universe. Is this what you intended to do?"),
    actions: [
      remindButton,
      cancelButton,
      launchButton,
    ],
  );

  // show the dialog
  showDialog(
    context: context,
    builder: (BuildContext context) {
      return alert;
    },
  );
}

Handling button presses

The onPressed callback for the buttons in the examples above were empty, but you could add something like this:

Widget launchButton = TextButton(
  child: Text("Launch missile"),
  onPressed:  () {
    Navigator.of(context).pop(); // dismiss dialog
    launchMissile();
  },
);

If you make the callback null, then the button will be disabled.

onPressed: null,

enter image description here

Supplemental code

Here is the code for main.dart in case you weren't getting the functions above to run.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter'),
        ),
        body: MyLayout()),
    );
  }
}

class MyLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: ElevatedButton(
        child: Text('Show alert'),
        onPressed: () {
          showAlertDialog(context);
        },
      ),
    );
  }
}

// replace this function with the examples above
showAlertDialog(BuildContext context) { ... }
Toiletry answered 19/12, 2018 at 3:10 Comment(12)
Navigator.of(context).pop(); does not dismiss the dialog, but the screen beneath it. The dialog presists.Subservience
@GunJack, It sounds like you are using a different setup than I have here. There is only a single screen in the example here.Toiletry
Yeah I think because I using multiple navigators. Calling showDialog directly in the button's onPressed method works. But calling showAlertDialog function from onPressed makes for the weird behaviour.Subservience
I tried this and the code after showAlertDialog runs immediately after the dialog pops up and doesnt wait for the choice to be done. How can I ensure the next code runs after a choice is selected? I tried using await and still no luckMystic
@West, put the code that you want to run afterward in the onPressed callback of the dialog button.Toiletry
Great answer! Also if you want to build your own custom dialog you can do it by using Dialog widget. It is as the same as above answer, but instead of using AlertDialog this class can return any custom widget that you build so it will be displayed as the popup. Read more in this medium articleRamiroramjet
Do I need to have bool state implementation in all widgets that needs to show the dialog component?Augustaugusta
@lolelo, what do you mean by bool state implementation?Toiletry
@Toiletry I missed that showDialog was a method from the package:flutter/src/material/dialog.dart. I thought I had to do conditional rendering to show the dialog.Augustaugusta
on Tap OK Button use Navigator.pop(context); For Go BackDumah
I'm getting this warning: The declaration showAlertDialog isn't referenced. Which results in dialog not showing up on Tap, how can I fix this?Thereat
Launching this missile will destroy the entire universe. Is this what you intended to do? -- did you press the Launch missile Button at last ?Adore
E
42

I used similar approach, but I wanted to

  1. Keep the Dialog code as a widget in a separated file so I can reuse it.
  2. Blurr the background when the dialog is shown.

enter image description here

Code: 1. alertDialog_widget.dart

import 'dart:ui';
import 'package:flutter/material.dart';


class BlurryDialog extends StatelessWidget {

  String title;
  String content;
  VoidCallback continueCallBack;

  BlurryDialog(this.title, this.content, this.continueCallBack);
  TextStyle textStyle = TextStyle (color: Colors.black);

  @override
  Widget build(BuildContext context) {
    return BackdropFilter(
      filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6),
      child:  AlertDialog(
      title: new Text(title,style: textStyle,),
      content: new Text(content, style: textStyle,),
      actions: <Widget>[
        new FlatButton(
          child: new Text("Continue"),
           onPressed: () {
            continueCallBack();
          },
        ),
        new FlatButton(
          child: Text("Cancel"),
          onPressed: () {
            Navigator.of(context).pop();
          },
        ),
      ],
      ));
  }
}

You can call this in main (or wherever you want) by creating a new method like:

 _showDialog(BuildContext context)
{

  VoidCallback continueCallBack = () => {
 Navigator.of(context).pop(),
    // code on continue comes here

  };
  BlurryDialog  alert = BlurryDialog("Abort","Are you sure you want to abort this operation?",continueCallBack);


  showDialog(
    context: context,
    builder: (BuildContext context) {
      return alert;
    },
  );
}
Eucalyptol answered 10/6, 2020 at 21:52 Comment(5)
You need to remove the dialog after user choose Continue option. So I needed to add Navigator.of(context).pop(); after continueCallback()Cherice
@ReginaldoRigo yes. I had to add it in my code as well. Just added it to the answer.Eucalyptol
This worked for me but I had to convert BlurryDialog to a StatefulWidget and declare the 2 Strings and VoidCallback as finals.Culinarian
How to alert error dialog using StatelessWidget?Vaporizer
I added working version of this below in 2023 without changing it to Stateful WidgetSeason
B
23

You can use this code snippet for creating a two buttoned Alert box,

import 'package:flutter/material.dart';

class BaseAlertDialog extends StatelessWidget {

  //When creating please recheck 'context' if there is an error!

  Color _color = Color.fromARGB(220, 117, 218 ,255);

  String _title;
  String _content;
  String _yes;
  String _no;
  Function _yesOnPressed;
  Function _noOnPressed;

  BaseAlertDialog({String title, String content, Function yesOnPressed, Function noOnPressed, String yes = "Yes", String no = "No"}){
    this._title = title;
    this._content = content;
    this._yesOnPressed = yesOnPressed;
    this._noOnPressed = noOnPressed;
    this._yes = yes;
    this._no = no;
  }

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: new Text(this._title),
      content: new Text(this._content),
      backgroundColor: this._color,
      shape:
          RoundedRectangleBorder(borderRadius: new BorderRadius.circular(15)),
      actions: <Widget>[
        new FlatButton(
          child: new Text(this._yes),
          textColor: Colors.greenAccent,
          onPressed: () {
            this._yesOnPressed();
          },
        ),
        new FlatButton(
          child: Text(this._no),
          textColor: Colors.redAccent,
          onPressed: () {
            this._noOnPressed();
          },
        ),
      ],
    );
  }
}

To show the dialog you can have a method that calls it NB after importing BaseAlertDialog class

_confirmRegister() {
var baseDialog = BaseAlertDialog(
    title: "Confirm Registration",
    content: "I Agree that the information provided is correct",
    yesOnPressed: () {},
    noOnPressed: () {},
    yes: "Agree",
    no: "Cancel");
showDialog(context: context, builder: (BuildContext context) => baseDialog);
}

OUTPUT WILL BE LIKE THIS

Output

Brandybrandyn answered 19/9, 2019 at 8:48 Comment(2)
How do I call this on an onTap function?Shofar
In Suragch's answer above, he has provided all the code to make an example app, where you tap the button and the dialog shows.Tetrameter
G
22

Here is a shorter, but complete code.

If you need a dialog with only one button:

await showDialog(
      context: context,
      builder: (context) => new AlertDialog(
        title: new Text('Message'),
        content: Text(
                'Your file is saved.'),
        actions: <Widget>[
          new FlatButton(
            onPressed: () {
              Navigator.of(context, rootNavigator: true)
                  .pop(); // dismisses only the dialog and returns nothing
            },
            child: new Text('OK'),
          ),
        ],
      ),
    );

If you need a dialog with Yes/No buttons:

onPressed: () async {
bool result = await showDialog(
  context: context,
  builder: (context) {
    return AlertDialog(
      title: Text('Confirmation'),
      content: Text('Do you want to save?'),
      actions: <Widget>[
        new FlatButton(
          onPressed: () {
            Navigator.of(context, rootNavigator: true)
                .pop(false); // dismisses only the dialog and returns false
          },
          child: Text('No'),
        ),
        FlatButton(
          onPressed: () {
            Navigator.of(context, rootNavigator: true)
                .pop(true); // dismisses only the dialog and returns true
          },
          child: Text('Yes'),
        ),
      ],
    );
  },
);

if (result) {
  if (missingvalue) {
    Scaffold.of(context).showSnackBar(new SnackBar(
      content: new Text('Missing Value'),
    ));
  } else {
    saveObject();
    Navigator.of(context).pop(_myObject); // dismisses the entire widget
  }
} else {
  Navigator.of(context).pop(_myObject); // dismisses the entire widget
}
}
Gesso answered 2/5, 2020 at 1:30 Comment(0)
C
17

Simply used this custom dialog class which field you not needed to leave it or make it null so this customization you got easily.

import 'package:flutter/material.dart';

class CustomAlertDialog extends StatelessWidget {
  final Color bgColor;
  final String title;
  final String message;
  final String positiveBtnText;
  final String negativeBtnText;
  final Function onPostivePressed;
  final Function onNegativePressed;
  final double circularBorderRadius;

  CustomAlertDialog({
    this.title,
    this.message,
    this.circularBorderRadius = 15.0,
    this.bgColor = Colors.white,
    this.positiveBtnText,
    this.negativeBtnText,
    this.onPostivePressed,
    this.onNegativePressed,
  })  : assert(bgColor != null),
        assert(circularBorderRadius != null);

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: title != null ? Text(title) : null,
      content: message != null ? Text(message) : null,
      backgroundColor: bgColor,
      shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(circularBorderRadius)),
      actions: <Widget>[
        negativeBtnText != null
            ? FlatButton(
                child: Text(negativeBtnText),
                textColor: Theme.of(context).accentColor,
                onPressed: () {
                  Navigator.of(context).pop();
                  if (onNegativePressed != null) {
                    onNegativePressed();
                  }
                },
              )
            : null,
        positiveBtnText != null
            ? FlatButton(
                child: Text(positiveBtnText),
                textColor: Theme.of(context).accentColor,
                onPressed: () {
                  if (onPostivePressed != null) {
                    onPostivePressed();
                  }
                },
              )
            : null,
      ],
    );
  }
}

Usage:

var dialog = CustomAlertDialog(
  title: "Logout",
  message: "Are you sure, do you want to logout?",
  onPostivePressed: () {},
  positiveBtnText: 'Yes',
  negativeBtnText: 'No');
showDialog(
  context: context,
  builder: (BuildContext context) => dialog);

Output:

enter image description here

Carillo answered 10/9, 2020 at 15:43 Comment(0)
V
12

Minumum code for alert dialog

showDialog(
  context: context,
  builder: (_) => AlertDialog(
    title: Text('Title'),
    content: Text(
      'Content widget',
    ),
  ),
);
Venation answered 19/6, 2022 at 12:58 Comment(0)
B
9

Or you can use RFlutter Alert library for that. It is easily customizable and easy-to-use. Its default style includes rounded corners and you can add buttons as much as you want.

Basic Alert:

Alert(context: context, title: "RFLUTTER", desc: "Flutter is awesome.").show();

Alert with Button:

Alert(
    context: context,
    type: AlertType.error,
    title: "RFLUTTER ALERT",
    desc: "Flutter is more awesome with RFlutter Alert.",
    buttons: [
    DialogButton(
        child: Text(
        "COOL",
        style: TextStyle(color: Colors.white, fontSize: 20),
        ),
        onPressed: () => Navigator.pop(context),
        width: 120,
    )
    ],
).show();

You can also define generic alert styles.

*I'm one of developer of RFlutter Alert.

Bidwell answered 20/12, 2018 at 16:31 Comment(2)
Nice. Looks like it could save some boilerplate and is pretty customizable.Toiletry
Is there a way to pass different functions to the onPressed parameter of the Alert so I don't have to keep making new alerts for everything??Shofar
S
5

If you want beautiful and responsive alert dialog then you can use flutter packages like

rflutter alert ,fancy dialog,rich alert,sweet alert dialogs,easy dialog & easy alert

These alerts are good looking and responsive. Among them rflutter alert is the best. currently I am using rflutter alert for my apps.

Sy answered 6/11, 2019 at 4:18 Comment(2)
links along with package names would be helpfulArron
I'm developer RFlutter Alert and thanks for your nice comment @raman raman .Bidwell
A
5
showAlertDialog(BuildContext context, String message, String heading,
      String buttonAcceptTitle, String buttonCancelTitle) {
    // set up the buttons
    Widget cancelButton = FlatButton(
      child: Text(buttonCancelTitle),
      onPressed: () {},
    );
    Widget continueButton = FlatButton(
      child: Text(buttonAcceptTitle),
      onPressed: () {

      },
    );

    // set up the AlertDialog
    AlertDialog alert = AlertDialog(
      title: Text(heading),
      content: Text(message),
      actions: [
        cancelButton,
        continueButton,
      ],
    );

    // show the dialog
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return alert;
      },
    );
  }

called like:

showAlertDialog(context, 'Are you sure you want to delete?', "AppName" , "Ok", "Cancel");
Androsphinx answered 25/4, 2020 at 15:23 Comment(0)
A
3

Check out Flutter Dropdown Banner to easily alert users of events and prompt action without having to manage the complexity of presenting, delaying, and dismissing the component.

To set it up:

import 'packages:dropdown_banner/dropdown_banner.dart';
...
class MainApp extends StatelessWidget {
  ...
  @override
  Widget build(BuildContext context) {
    final navigatorKey = GlobalKey<NavigatorState>();
    ...
    return MaterialApp(
        ...
        home: DropdownBanner(
          child: Scaffold(...),
          navigatorKey: navigatorKey,
        ),
    );
  }
}

To use it:

import 'packages:dropdown_banner/dropdown_banner.dart';
...
class SomeClass {
  ...
  void doSomethingThenFail() {
    DropdownBanner.showBanner(
      text: 'Failed to complete network request',
      color: Colors.red,
      textStyle: TextStyle(color: Colors.white),
    );
  }
}
Click here to see an example
Ardis answered 18/9, 2019 at 15:38 Comment(2)
When posting links as answers, try to add some actual text/code to explain why you gave the link, and/or how to use the linked content. Otherwise, such replies should be comments.Isaacson
@Adrian I added some example code as per your recommendation.Ardis
V
2

If you need a dialog so this code for you. just use showMyDialog() onPress or any inside a function.

 void showMyDialog() {
  showDialog(
  context: context,
  builder: (ctx) => AlertDialog(
    title: const Text("Login Failed!"),
    content: const Text(
      "Invalid credential !! Please check your email or password",
      style: TextStyle(fontSize: 18, fontWeight: FontWeight.w400),
    ),
    actions: <Widget>[
      TextButton(
        onPressed: () {
          Navigator.of(ctx).pop();
        },
        child: Container(
          child: const Text(
            "Try again",
            style: TextStyle(color: Colors.cyan, fontSize: 17),
          ),
        ),
      ),
    ],
  ),
)}

Demo dialog screenshots

hope its helpful😊😊😊

Vermiculation answered 26/9, 2022 at 10:0 Comment(0)
P
1

Just to add to the great answers - the best package I found is:

adaptive_dialog: ^1.8.0+1

For a one OK button the best thing I found is using showOkAlertDialog

Implementation:

import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:flutter/material.dart';

    Widget build(BuildContext context) {
      return Container(
        child: Center(
            child: IconButton(
          icon: Icon(
            Icons.info,
          ),
          onPressed: () => showOkAlertDialog(
            context: context,
            okLabel: 'OK',
            title: 'Title',
            message: 'This is the message',
          ),
        )),
      );
    }

Clean and dismisses when you click 'Ok'.

Peppergrass answered 11/9, 2022 at 14:34 Comment(0)
A
1

Simple and working solution that I used: Enjoy // Sample can be used for exit dialog box on apps

showAlertDialog(BuildContext context) {

    Widget okButton = TextButton(
      child: const Text("Leave now",style: TextStyle(color: Colors.red),),
      onPressed: () { SystemNavigator.pop(); },
    );

    Widget nopeButton = TextButton(
      child: const Text("Stay here"),
      onPressed: () { Navigator.pop(context); },
    );

    AlertDialog alert = AlertDialog(
      title: const Text("Leave"),
      content: const Text("Are you sure you want to leave?"),
      actions: [
        nopeButton,
        okButton,
      ],
    );

    showDialog(
      context: context,
      builder: (BuildContext context) {
        return alert;
      },
    );
  }
Arita answered 12/10, 2022 at 14:1 Comment(0)
S
1

Here is working version of Bakri Bitar's answer without changing it to Stateful Widget:

import 'dart:ui';
import 'package:flutter/material.dart';


class BlurryDialog extends StatelessWidget {
  final String title;
  final String content;
  final VoidCallback continueCallBack;
  final TextStyle textStyle = const TextStyle(color: Colors.black);

  const BlurryDialog({
    Key? key,
    required this.title,
    required this.content,
    required this.continueCallBack,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BackdropFilter(
      filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6),
      child:  AlertDialog(
        shape: RoundedRectangleBorder(    // This line is added
            borderRadius: BorderRadius.circular(12),   // Change this value to change the corner radius
        ),
        title: Text(title, style: textStyle, textAlign: TextAlign.center,),
        content: new Text(content, style: textStyle,),
        actions: <Widget>[
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              ElevatedButton(
                child: Text('Yes', style: TextStyle(color: Colors.white)),
                onPressed: () {
                       continueCallBack();
                  Navigator.of(context).pop();
              
                },
                style: ElevatedButton.styleFrom(
                  backgroundColor: Color.fromARGB(255, 54, 139, 244),
                  foregroundColor: Colors.black,
                ),
              ),
               ElevatedButton(
                child: Text('No', style: TextStyle(color: Colors.white)),
                onPressed: () {
                  Navigator.of(context).pop();
                },
                style: ElevatedButton.styleFrom(
                  backgroundColor: Color.fromARGB(255, 54, 139, 244),
                  foregroundColor: Colors.black,
                ),
              ),
            ]),
        ],
      ),
    );
  }
}

You can call it like this:

VoidCallback continueCallBack = () {
  Navigator.of(context).pop();
  // code on continue comes here
};

BlurryDialog alert = BlurryDialog(
  title: "Your Title",         // Provide 'title'
  content: "Your Content Text",        // Provide 'content'
  continueCallBack: continueCallBack,   // Provide 'continueCallBack'
);

showDialog(
  context: context,
  builder: (BuildContext context) {
    return alert;
  },
);
Season answered 28/5, 2023 at 1:46 Comment(0)
F
0

Another easy option to show Dialog is to use stacked_services package

 _dialogService.showDialog(
      title: "Title",
      description: "Dialog message Tex",
         );
     });
Financier answered 25/12, 2020 at 18:21 Comment(0)
M
0

This code works and demonstrates how to obtain the button value pressed by the user:

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: _title,
      home: Scaffold(
        appBar: AppBar(title: const Text(_title)),
        body: const Center(
          child: MyStatelessWidget(),
        ),
      ),
    );
  }
}

class MyStatelessWidget extends StatelessWidget {
  const MyStatelessWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return TextButton(
      onPressed: () {
        // set up the buttons
        Widget cancelButton = TextButton(
          child: Text("Cancel"),
          onPressed: () => Navigator.pop(context, 'Cancel'),
        );
        Widget continueButton = TextButton(
          child: Text("Ok"),
          onPressed: () => Navigator.pop(context, 'Ok'),
        );
        showDialog<String>(
          context: context,
          builder: (BuildContext context) => AlertDialog(
            title: const Text('AlertDialog Title'),
            content: const Text('AlertDialog description'),
            actions: <Widget>[
              cancelButton,
              continueButton,
            ],
          ),
        ).then((value) => print(value));
      },
      child: const Text('Show Dialog'),
    );
  }
}

Pressing on Ok button. then on Cancel button print enter image description here

enter image description here

Maxine answered 19/6, 2022 at 8:0 Comment(0)
E
0
showDialog<String>(
  context: context,
  builder: (BuildContext context) =>
      AlertDialog(
    title: const Text(
      'Invalid Password',
      style: TextStyle(color: Colors.red),
    ),
    content:
        const Text('Create Strong Password'),
    actions: <Widget>[
      Center(
        child: TextButton(
          style: TextButton.styleFrom(
            primary: Colors.white,
            backgroundColor: Colors
                .red, // Background Color
          ),
          onPressed: () => Navigator.pop(
              context, 'Cancel'),
          child: const Text('Cancel'),
        ),
      ),
    ],
  ),
),
Erastian answered 26/8, 2022 at 4:42 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Dyanna
F
0
showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: const Text("Storage Permission Required"),
          content: const Text(
              "Please grant storage permission to download files."),
          actions: <Widget>[
            TextButton(
              // Use TextButton instead of FlatButton
              child: const Text("CANCEL"),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
            TextButton(
              // Use TextButton instead of FlatButton
              child: const Text("SETTINGS"),
              onPressed: () {
                openAppSettings(); // Open app settings
              },
            ),
          ],
        );
      },
    );
Flavoprotein answered 6/2 at 12:31 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Dyanna

© 2022 - 2024 — McMap. All rights reserved.