Flutter prevent close dialog on back pressed - flutter

I am using the showDialog function to build a dialog box, but I need to avoid that when the user presses the back button, the dialog box does not close, this is my code:
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
title: new Text("Hello"),
content: new SingleChildScrollView(
child: Container(),
actions: <Widget>[
// usually buttons at the bottom of the dialog
new FlatButton(
child: new Text("Close"),
onPressed: () {
},
),
],
);
},
);
How can I get it to not close?

You need to enclose your AlertDialon on a WillPopScope like this:
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return WillPopScope(
onWillPop: (){},
child:AlertDialog(
title: new Text("Hello"),
content: new SingleChildScrollView(
child: Container(),),
actions: <Widget>[
// usually buttons at the bottom of the dialog
new FlatButton(
child: new Text("Close"),
onPressed: () {
},
),
],
)
)
},
);
The WillPopScope provides you a onWillPop parameter, where you can pass a function of what you want when the child pop. In this case, the parameter receive an empty function so it wont pop.

You need to use a WillPopScope. It will use the function on onWillPop to determine if the dialog closes or not. In this case always false, so the user can't use the back button to close the dialog.
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return WillPopScope(
child: AlertDialog(
title: new Text("Hello"),
content: new SingleChildScrollView(
child: Container(),
),
actions: <Widget>[
// usually buttons at the bottom of the dialog
new FlatButton(
child: new Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
onWillPop: () async {
return false;
},
);
},
);

You can also do it by setting onWillPop: () => Future.value(false) inside WillPopScope. Right now onWillPop:(){} as mentioned in Accepted answer gives warning.
Warning Message: This function has a return type of 'Future', but doesn't end with a return statement.
Try adding a return statement, or changing the return type to 'void'.
So, use onWillPop: () => Future.value(false) or onWillPop: () async {return false;}, instead.
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return WillPopScope(
child: AlertDialog(
................
),
onWillPop: () => Future.value(false),
);
},
);

If you are using Getx Dialog then use like this:
Get.defaultDialog(
titlePadding: EdgeInsets.all(0),
title: "",
barrierDismissible: false,
radius: 10,
onWillPop: () => Future.value(false),
content:Container());

Related

How use alert dialog flutter

I try building alert function, but this error follow return:
Undefined name 'context'.
Try correcting the name to one that is defined, or defining the name.
Future<void> _showAlertDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
// <-- SEE HERE
title: const Text('Cancel booking'),
content: SingleChildScrollView(
child: ListBody(
children: const <Widget>[
Text('Are you sure want to cancel booking?'),
],
),
),
actions: <Widget>[
TextButton(
child: const Text('No'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('Yes'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
I would like to click on a certain elevatedbutton to open the alert dialog
Try to pass the current BuildContext to your function
Future<void> _showAlertDialog(BuildContext context) async {

How to enable/disable dialog buttons (actions)

I have a helper function to create dialogs in my flutter app:
Future<void> showContentDialog(BuildContext context,
{required Widget content, String? title, List<Tuple2<String, void Function()>>? actions}) async {
Widget? titleWidget;
if (title != null) {
titleWidget = Text(
title,
style: Theme.of(context).textTheme.titleSmall!.copyWith(fontWeight: FontWeight.bold),
);
}
var dialogActions = <Widget>[];
if (actions != null) {
dialogActions.addAll(
actions.map(
(a) => TextButton(
child: Text(a.item1),
onPressed: () {
a.item2();
}),
),
);
}
await showDialog(
context: context,
barrierDismissible: true,
builder: (context) => AlertDialog(
title: titleWidget,
content: SizedBox(width: ThemeHelpers.maxPopupWidth, child: content),
actions: dialogActions,
),
);
}
There is another similar one that is used on Apple devices that uses equivalent widgets.
I can easyly manage state on the content portion of the dialog by wrapping it in a StatefulBuilder, but how can I enable and disable the dialog buttons (the actions passed to the AlertDialog) builder depending on content state?
My first idea was to add another a ValueNotifier parameter to the action builders and wrap them in ValueListenerBuilders but that didn't work.
Do I have any way of doing that other than including the actions as buttons inside the content (were I can easyly manage their state)?
You can pass null on onPressed to disable the button state. While it is not clear from where you like to controll the state, you can use ValueNotifier, and it work for all widget
final ValueNotifier<bool> enableButton = ValueNotifier(false);
Future<void> showContentDialog(
BuildContext context,
) async {
await showDialog(
context: context,
barrierDismissible: true,
builder: (context) => AlertDialog(
content: SizedBox(
width: 222,
child: Column(
children: [
Text("A"),
ElevatedButton(
onPressed: () {
enableButton.value = !enableButton.value;
},
child: Text("toggleButtonState"),
)
],
),
),
actions: [
ValueListenableBuilder<bool>(
valueListenable: enableButton,
builder: (context, value, child) => ElevatedButton(
onPressed: value ? () {} : null,
child: Text("BTN"),
),
),
],
),
);
}
In content add column and add dialog widgets in it
await showDialog(
context: context,
barrierDismissible: true,
builder: (context) => AlertDialog(
title: titleWidget,
content: Column(
mainAxisSize: MainAxisSize.min,
children : [
SizedBox(width: ThemeHelpers.maxPopupWidth, child: content),
dialogActions,
]
)
),
);

How to disable onBackPressed() for AlertDialog flutter

I've got an AlertDialog() that it's barrierDismissible has been set to false. But yet when user presses the back button on android device the AlertDialog closes. How can I compeletly prevent the user from closing the AlertDialog()?
Here's what I've done so far:
return showDialog<bool>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Title'),
content: Text('This is the alert dialog content'),
actions: <Widget>[
FlatButton(
child: Text('ok'),
onPressed: () {
Navigator.of(context).pop();
print('ok you win');
},
),
],
);
},
);
Try this way use WillPopScope() to handle onBackPressed() event
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return WillPopScope(
onWillPop: () {return Future.value(false);},
child: return AlertDialog(
title: Text('Title'),
content: Text('This is the alert dialog content'),
actions: <Widget>[
FlatButton(
child: Text('ok'),
onPressed: () {
Navigator.of(context).pop();
print('ok you win');
},
),
],
),
);
});
You can use the WillPopScope as a parent of the AlertDialog
showDialog(context: context,builder: (BuildContext context)
{
return WillPopScope(
onWillPop: () async =>false,
child: AlertDialog(
title: Text('Title'),
content: Text('Sample'),
actions: <Widget>[
FlatButton(
child: Text('ok'),
onPressed: (){
Navigator.of(context).pop();
},
)
],
),
);

Counter Inside AlertDialog - Flutter

I am using an AlertDialog for my application and inside i build an counter. Value of counter does not get updated automatically. i used "setState({})", but it does not help, because it only rebuilds the build() function and not the int _value inside Dialog.
Anyone familiar to this problem and help me out?
Thank you
The code sample below solved my problem. As #anmol.majhail nicely referred, a wrote my AlertDialog inside a new class, which was then called by the build() function. To call the class and show AlertDialog i used to do this.
Widget createItem() {
return new FloatingActionButton(
elevation: 4.0,
child: const Icon(Icons.create),
onPressed: () {
showDialog(
context: context,
child: new ItemAlertView()
);
},
);
}
This example helped me out (compare to line 59). https://gist.github.com/harshapulikollu/5461844368e95c6d3a38fffe72f03eee
User StatefulBuilder to return AlertDialog.
showDialog(
context: context,
builder: (context) {
String contentText = "Initial Content";
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text("Title Here"),
content: Text(contentText),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.pop(context),
child: Text("Cancel"),
),
FlatButton(
onPressed: () {
setState(() {
contentText = "Changed!";
});
},
child: Text("Change Now"),
),
],
);
},
);
},
);
Cleanest way, in my opinion, would be to use a Stream with a StreamBuilder.

How to prevent AlertDialog from not closing by clicking outside?

I built an AlertDialog to display Loading while i'm authenticating the user and when it finishes i pop it.
Widget loadingDialog = new AlertDialog(
content: new Row(
children: <Widget>[
new CircularProgressIndicator(),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: new Text("Loading..."),
),
],
),);
But, if the user taps outside the Dialog it closes. So when the auth finishes, it will still pop something (i guess the scaffol), breaking the app.
How can i make Dialog not closable?
There is a property inside showDialog called barrierDismissible. Setting this value to false will make your AlertDialog not closable by clicking outside.
showDialog(
...
barrierDismissible: false,
...
To prevent dismissing of dialog on press of a back button, you should also wrap your AlertDialog (or any other widget) inside a WillPopScope.
showDialog(
context: context,
barrierDismissible: false, // <-- Set this to false.
builder: (_) => WillPopScope(
onWillPop: () async => false, // <-- Prevents dialog dismiss on press of back button.
child: AlertDialog(...),
),
);
// User Defined Function
void _showloding() {
// flutter defined function
showDialog(
barrierDismissible: false, // JUST MENTION THIS LINE
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
content: Padding(
padding: const EdgeInsets.all(20.0),
child: Container(height: 100,width: 100,child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(child: SizedBox(height: 50,width: 50,child: CircularProgressIndicator())),
Padding(
padding: const EdgeInsets.only(top: 20),
child: Center(child: Text("Processing")),
)
],
)),
)
);
},
);
}
If you want to prevent dialog close when back button pressed then refer below code. You need to wrap the AlertDialog in WillPopScope widget and make onWillPop property value with function which return Future.value(false).
showDialog(
barrierDismissible: false, //this will prevent popup closing when touch outside of popup
context: context,
builder: (BuildContext context) {
return WillPopScope( // Wrap in WillPopScope widget
onWillPop: () => Future.value(false), //this line will prevent popup closing when back button of phone press
child:AlertDialog(
title: new Text("Alert Title"),
content: new SingleChildScrollView(
child: Container(),),
actions: [
new FlatButton(
child: new Text("Close"),
onPressed: () {
},
),
],
)
)
},
);