I have an alert dialog that I want to be dismissed when clicked outside of it, I know this is the default behavior of alert dialogs in flutter, but I don't know what's the problem that's preventing it from closing when clicked outside.
I tried to use barrierDismissable to true, but still, it doens't work.
This is my dialog :
termsAndConditionsDialog(BuildContext context) {
AlertDialog alert = AlertDialog(
title: Text("Terms and Conditions", style: TextStyle(fontSize: 18, color: AppColors.accentColor),),
content: Text(
generalSettings.policyForCustomer,
style: TextStyle(fontSize: 16),
),
);
// show the dialog
showDialog(
barrierDismissible: true,
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
and this is how I call it from button's onPressed :
termsAndConditionsDialog(context);
call this upon onPressed or onTap:
void showMessage(){
showDialog(
context:context,
builder: (Buildcontext context){
return AlertDialog(
backgroundColor: Colors.transparent,
content: Container(
width: MediaQuery.of(context).size.width,
height: 100,
alignment: AlignmentDirectional.center
child: Text("TRIAL",style: TextStyle(color: Colors.white))
)
)
}
)
}
Custom Alert method
typedef ResponseCallbackValueLess = void Function();
showAlertDialogWithOkButton(
BuildContext context,
String message,
String heading,
String buttonAcceptTitle,
ResponseCallbackValueLess callback) {
Widget continueButton = FlatButton(
child: Text(buttonAcceptTitle),
onPressed: () {
callback();
},
);
called like below:
showAlertDialogWithOkButton(context,
'No items found in your cart.',
"app name", "Ok", dismissAlert(context));
dismissAlert(context){
Navigator.pop(context);
}
Related
I have a dialog that appears after user click on send button . When dialog appears , I want to show a text after 5 seconds . I use Future.delayed but the text doesn't appear at all . It appears only when I close the dialog and open it again . I want to show the text after 5 seconds from opening the dialog .
Here is my function
void _initialize() {
Future<void>.delayed(const Duration(seconds: 3), () {
if (mounted) {
setState(() {
visibility = true;
});
}
});
}
}
And here is my dialog code in the onTab of the button
_initialize()
showDialog(context: context,
barrierDismissible: false,
builder: (BuildContext contextd){
return WillPopScope(
onWillPop: () {return Future.value(false);},
child: Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)
),
child: Padding(
padding: EdgeInsets.fromLTRB(20.w, 20.h, 20.w, 20.h),
child: Column(
children: [
//here are some widgets
Visibility(
visible:visibility?true:false,
child: Text("Resend?",style: TextStyle(decoration:
TextDecoration.underline,),)),
],),
),
),
);
});
Try using StatefulBuilder like this:
showDialog(
context: context,
builder: (BuildContext context) => StatefulBuilder(
builder: (context, setState) {
return //somthing to return;
},
));
This happens because your setState that update visibility has a different context than builder dialog. Visibility is actually update but only appear in dialog when close and open again because this is how build dialog is updated. If you want to work with the context dialog need to use that widget:
StatefulBuilder(
builder: (context, setState) {
Into your dialog and then call that setState.
Try using a StatefulBuilder. Using the bool visible and the setDialogState argument, you can update the state of the contents of the dialog.
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return StatefulBuilder(
builder(context, setDialogState) {
// this variable is used for the conditional display
bool visible = false;
// this future will update the visible variable in 3 seconds, after the dialog is displayed already
Future.delayed(Duration(seconds: 3)).then(() => setDialogState(() { visible = true;}));
return WillPopScope(
onWillPop: () { return Future.value(false); },
child: Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)
),
child: Padding(
padding: EdgeInsets.fromLTRB(20.w, 20.h, 20.w, 20.h),
child: Column(
children: [
//here are some widgets
Visibility(
visible:visible,
child: Text(
"Resend?",
style: TextStyle(
decoration: TextDecoration.underline,
),
),
),
],
),
),
),
);
},
);
};
For the elevated button, I would like to show the visible/hide part content through setState. However, I could do it in normal pages but not a Dialog.
Here's the code:
bool addmaterial = true;
ClipRRect(
borderRadius: BorderRadius.circular(50),
child: SizedBox(
height: 40,
width: 400,
child: ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(
Color(0xfff4f4f4)),
),
onPressed: () {
addmaterial = !addmaterial;
},
Try adding a StateFulBuilder inside your showDialog widget. If you want to change the state inside the showDialog
showDialog(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
actions: <Widget>[],
content: Container(),
);
},
);
},
);
I have a widget with an icon when I click on it a dialog widget is shown, here is the call for the dialog :
// this icon is in widget parent
IconButton(
icon: Icon(
Icons.info_outline,
size: mobileWidth * 0.07,
),
tooltip: 'information',
color: Colors.blueGrey,
onPressed: () {
showAlertInfo(context, code);
setState(() {});
},
),
here is my dialog :
showAlertInfo(BuildContext context, String code) {
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text(
"Information sur le client $code", ),
content: SingleChildScrollView(
child: Container( .....
/* ...
this dialog has some operations that changes info
values of the widget that called this in first place
it is a big code to put here*/
// here I have a close button
actions: [
FlatButton(
child: Text(
"Fermer",
style: TextStyle(
color: Colors.red,
fontSize: mobileWidth * 0.035,
fontWeight: FontWeight.bold,
),
),
onPressed: () {
Navigator.of(context).pop(); // dismiss dialog
},
),
],
);
what I'm trying to achieve is when the dialog is dismissed I want the parent widget to be updated, so how I call setState of the parent widget when the dialog widget is closed ?
For Async function
Add await before showDialog() and call setState((){}) on the next line.
await showDialog(
context: context,
builder: (context) {
return yourWidget;
}
);
setState((){});
For Sync Function
Use the .then() callback, and call setState((){}) in it.
showDialog(
context: context,
builder(context) {
return yourWidget;
}).then((_){
setState((){});
}
);
I am using below code to register the user, there is an option to upload image , if it is null the user won't be registered, that is working accurately, only thing I am facing is that if the image is null it should the alert dialog to the user , but the alert dialog is not working at all.
How should I implement the alert dialog?
if (avatarImageFile != null ) {
FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: emailInputController.text,
password: pwdInputController.text)
.then((currentUser) =>
Firestore.instance
.collection("users")
.document(currentUser.user.uid)
.setData({
"username": userNameInputController.text,
"email": emailInputController.text,
})
.then((result) =>
{
uploadFile(currentUser.user.uid),
print(currentUser.user.getIdToken()),
currentUser.user.sendEmailVerification(),
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) =>
MainScreen(
)),
(_) => false),
})
.catchError((err) => print(err)))
.catchError((err) => print(err));
}
else {
print("Please Upload the Image");
AlertDialog(
title: Text("Image Required"),
content: Text("Please upload the image"),
actions: <Widget>[
FlatButton(
child: Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
}
You need to use the function showDialog so the dialog appears:
else {
print("Please Upload the Image");
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Image Required"),
content: Text("Please upload the image"),
actions: <Widget>[
FlatButton(
child: Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
};
);
}
Peter Haddad's answer solves the problem but I would suggest placing the AlertDialog in a widget so that it would be easy to reuse the AlertDialog again. Here is how I did it for my project:
Dialogs.dart:
import 'package:flutter/material.dart';
enum alertDialogAction { cancel, save }
class Dialogs {
static Future<alertDialogAction> alertDialog(
BuildContext context,
String title,
String body,
String cancel,
String save,
) {
Future<alertDialogAction> action = showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
title: Text(title),
content: Text(body),
actions: <Widget>[
FlatButton(
onPressed: () =>
Navigator.pop(context, alertDialogAction.cancel),
child: Text(cancel)),
RaisedButton(
color: Colors.orange,
onPressed: () =>
Navigator.of(context).pop(alertDialogAction.save),
child: Text(
save,
style: TextStyle(color: Colors.white),
)),
],
);
});
return (action != null) ? action : alertDialogAction.cancel;
}
Here is how you can call it:
onPressed:() async {
final action= await Dialogs.alertDialog(context,"Title","Body","Cancel","Save");
//cancel and save are the button text for cancel and save operation
if(action==alertDialogAction.save){
//do something
Navigator.pop(context);
}
}
You can also show a dialog box using scaffold, for example,
Scaffold.of(context).showSnackBar(SnackBar(content: AlertDialog(content: Text('Alert!!!'))));
But you have to keep in mind that context should be of the current scaffold.
So you might want to wrap the body property (in Scaffold) in a Builder Widget and then when you use context inside that builder widget, that context will be of current scaffold.
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Your Title!!!"),
content: Text("Your Content!!!"),
actions: <Widget>[
FlatButton(
child: Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
};
);
I want to show a dialog when user long pressed on an item and pop it when finger up but it can't detect tap up.
I put dialog on another GestureDetector and use onTapUp property of it to pop dialog.
GestureDetector(
child: studentIcon(index, context),
onLongPress: () {
showDialog(
context: context,
builder: (context) {
return GestureDetector(
onTapUp: (detail) {
Navigator.pop(context);
},
child: DialogDetail(
index: index,
),
);
});
},
I expect to pop dialog after finger up after long pressed.
You can't do that as there is an context problem in GestureDetector.
Please follow this answer to implement this thing.
Try to make method to open dialog . i provide alert dialog code..
void _showText(BuildContext context) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
content: Text(
"User name :${nameEditText.text} \nPassword : ${passwordEditText.text}"),
actions: <Widget>[
new FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: new Text("OK"))
],
);
});
}
}
after that called on button click..
child: RaisedButton(
padding: EdgeInsets.all(15.0),
onPressed: () {
_showText(context);
},
child: Text(
"Submit",
style: TextStyle(fontSize: 15, color: Colors.white),
),
color: Colors.blue,
),