How do I dismiss an Alert Dialog in Flutter? - flutter

I am using an Alert Dialog for the popups in my app. When the onTap is triggered the popup gets called however when I press the 'Cancel' button the popup does not dismiss and the whole screen behind the popup goes black.
This is my code for the popup.
import 'package:flutter/material.dart';
class FancyAlertDialog {
static showFancyAlertDialog(
BuildContext context,
String title,
String message,
{
bool dismissable = true,
Icon icon,
#required String labelPositiveButton,
#required String labelNegativeButton,
#required VoidCallback onTapPositiveButton,
#required VoidCallback onTapNegativeButton,
}) {
assert(context != null, 'context is null!!!');
assert(title != null, 'title is null!!!');
assert(message != null, 'message is null!!!');
assert(labelPositiveButton != null, 'labelPositiveButton is null');
assert(labelNegativeButton != null, 'labelNegativeButton is null');
assert(onTapPositiveButton != null, 'onTapPositiveButton is null');
assert(onTapNegativeButton != null, 'onTapNegativeButton is null');
return showDialog(
context: context,
barrierDismissible: dismissable,
child: Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(4.0),
),
),
child: Wrap(
children: <Widget>[
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(4.0),
topRight: Radius.circular(4.0),
),
color:Colors.red,
),
padding: EdgeInsets.symmetric(vertical: 5.0),
child: Stack(
children: <Widget>[
Align(
child: icon ?? Container(height:0),
alignment: Alignment.topRight,
)
],
),
),
Padding(
padding: EdgeInsets.only(
left: 16.0,
top: 2.0,
right: 16.0,
bottom: 8.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Center(
child: Text(
title,
style: Theme.of(context).textTheme.subtitle,
),
),
SizedBox(height: 8.0),
Text(
message,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.caption,
),
SizedBox(height: 16.0),
Row(
children: <Widget>[
Expanded(
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(16.0),
),
),
color: Colors.grey,
child: Text(
labelNegativeButton.toUpperCase(),
style: TextStyle(
color: Colors.white,
),
),
onPressed: onTapNegativeButton,
),
),
SizedBox(width: 16.0),
Expanded(
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(16.0),
),
),
color: Colors.red,
child: Text(
labelPositiveButton.toUpperCase(),
style: TextStyle(
color: Colors.white,
),
),
onPressed: onTapPositiveButton,
),
),
],
)
],
),
),
],
),
),
);
}
}
And this is how I've called the popup.
FancyAlertDialog.showFancyAlertDialog(
context,
'Info Fancy Alert Dialog Box',
'This is a info alert dialog box. This plugin is used to help you easily create fancy dialog',
icon: Icon(
Icons.clear,
color: Colors.black,
),
labelPositiveButton: 'OKAY',
onTapPositiveButton: () {
Navigator.pop(context);
print('tap positive button');
},
labelNegativeButton: 'Cancel',
onTapNegativeButton: () {
Navigator.pop(context);
print('tap negative button');
},
);
This is what my screen looks like when I press the cancel button:

Try this inside your onTap():
Navigator.of(context, rootNavigator: true).pop();

I assume you are using the wrong context object when calling Navigator.pop(context).
At that point the Navigator isn't aware of the dialog yet.
First, provide a new BuildContext within showDialog. There are two ways to do that:
Create a new widget for the child parameter (now Dialog) in the showDialog function.
Wrap the child (Dialog) with a Builder that provides a new BuildContext
Then you should get that new context to the Navigator.pop(context) call. Again, there are two ways to do that:
Pop from within the dialog itself
Pass the context object along as a parameter to the onTapPositiveButton and onTapNegativeButton
More info on the Builder can be found here as well: https://www.youtube.com/watch?v=xXNOkIuSYuA

Try to use this
onTap: () => Navigator.of(context).pop(false),

Related

How to make each _buildrow go the next page in Flutter?

i got problem when i dont know to make each buildrow go to each page?this is for buildDrawer can you help me with this?
builDrawer fuction this for profile screen.dart
_buildDrawer() {
return ClipPath(
clipper: OvalRightBorderClipper(),
child: Drawer(
Container(
height: 90,
alignment: Alignment.center,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient:
LinearGradient(colors: [Colors.pink, Colors.red])),
child: CircleAvatar(
radius: 40,
backgroundImage: NetworkImage(profile),
),
),
SizedBox(height: 5.0),
Text(
"Mohd Amin bin Yaakob",
style: TextStyle(color: Colors.white, fontSize: 18.0),
),
Text(
"Pegawai",
style: TextStyle(color: active, fontSize: 16.0),
),
SizedBox(height: 30.0),
_buildRow(Icons.home, "Home"),
_buildDivider(),
_buildRow(Icons.person_pin, "Your profile"),
_buildDivider(),
_buildRow(Icons.settings, "Settings"),
_buildDivider(),
_buildRow(Icons.email, "Contact us"),
_buildDivider(),
_buildRow(Icons.info_outline, "Help"),
_buildDivider(),
],
),
),
),
),
),
);
}
How to make Functional Navigator each buildRow
You need to make rows with clickable widgets like listtile.
Try this inside your _buildRow()
Widget _buildRow(IconData icon, String title) {
final TextStyle tStyle = TextStyle(color: active, fontSize: 16.0);
return ListTile(
title: Text( title, style: tStyle, ),
leading: Icon( icon, color: active, ),
onTap: () {
// Your navigation code here
},
);
}
You can remove the container as well and try contentPadding in ListTile
Its explained in the drawer documentation https://docs.flutter.dev/cookbook/design/drawer
You can require an onTap function in your _buildRow method. Also wrap you Container inside an InkWell widget and this function in onTap property.
Following is the revised code:
Widget _buildRow(IconData icon, String title, VoidCallback onTap) {
final TextStyle tStyle = TextStyle(color: active, fontSize: 16.0);
return InkWell(
child: Container(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Row(
children: [
Icon(
icon,
color: active,
),
SizedBox(width: 10.0),
Text(
title,
style: tStyle,
),
],
),
),
onTap: onTap,
);
}
When calling the above function, provide the onTap callback like this:
_buildRow(Icons.home, "Home", () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return HomePage();
},
),
);
});

How to watch when the Slidable changes state on Flutter

I'm utilize o Slidable on app Flutter and put as ListTile child.
So far ok.
I'm problem is i would like when I slide it to the left the text keeps appearing on the screen, as shown in the image below.(Red == Title)
At the moment the text is hidden when I swipe, as per the image.(Red == Title)
I saw that when I swipe this attribute changes state Slidable.of(context)?.animation.isCompleted
And I also verified that in my Row title of ListTile, if I line up the title as End, the title will appear msm by swiping.
So I thought, as this Slidable.of(context)?.animation.isCompleted attribute changes state I align my Row to Start or End.
But I couldn't find a way to monitor this attribute, so that when it changes I can rebuild my Row. I tried to put it as Stream but I wasn't successful. Because it looks like it doesn't generate an event, it just changes the value.
I don't know how I could do it, if anyone has any tips...
Code:
#override
Widget build(BuildContext) {
return Slidable(
key: const ValueKey(1),
endActionPane: ActionPane(
motion: const DrawerMotion(),
children: [
SlidableAction(
onPressed: (ctx) => {
Get.to(() => const CredentialOperationScreen(),
arguments:
RouteDetailCredential(itemCredential: itemCredential))
},
backgroundColor: ConstsColors.orangeAccent,
foregroundColor: Colors.white,
icon: Icons.info_outline,
),
SlidableAction(
onPressed: (ctx) => {
Get.to(() => const CredentialOperationScreen(),
arguments:
RouteDeleteCredential(itemCredential: itemCredential))
},
backgroundColor: const Color.fromRGBO(219, 32, 32, 1),
foregroundColor: Colors.white,
icon: Icons.delete_outline,
),
],
),
child: Builder(
builder: (ctx) {
return Container(
child: _listTile(ctx),
decoration: const BoxDecoration(
border: Border(
bottom:
BorderSide(color: ConstsColors.greyColorOpacity))));
},
));
}
Widget _listTile(context) {
return ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Icon(
itemCredential.icon,
color: Colors.black,
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
itemCredential.name,
style: const TextStyle(
fontFamily: 'Roboto',
fontSize: 16,
),
),
),
],
),
onTap: () => {
Slidable.of(context)?.animation.isCompleted == true
? Slidable.of(context)?.close()
: Slidable.of(context)?.openEndActionPane()
},
trailing: const Icon(Icons.check_circle_outline, color: Colors.green),
);
}

Passing function as parameter to a widget

I have a button that calls a widget to open a custom dialog:
child: GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (context){
return MovMapAlert(
titulo: "yasiguiendo".tr(),
texto: "dejarsiguiendo".tr(),
aceptar: "dejardeseguir".tr(),
cancelar: "cancelar".tr(),
funcion: SeguidoresCrud().dejarDeSeguir(documentIdSeguidores),);
});
},
child: Image.asset('assets/profile/boton_follow_rojo.png'),
)
)
As you may see,I am posting some parameters to the custom dialog widget, including a function that should be executed when the user taps on a dialog button.
Here you have the custom dialog widget:
class MovMapAlert extends StatelessWidget {
final String titulo;
final String texto;
final String aceptar;
final String cancelar;
final Function funcion;
const MovMapAlert({Key key, this.titulo, this.texto, this.aceptar, this.cancelar, this.funcion}) : super(key: key);
#override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16)
),
elevation: 0,
backgroundColor: Colors.transparent,
child: _buildChild(context),
);
}
_buildChild(BuildContext context) => Container(
height: 350,
decoration: BoxDecoration(
color: Colors.redAccent,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(Radius.circular(12))
),
child: Column(
children: <Widget>[
Container(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Image.asset('assets/images/movmap_transparente1024.png', height: 120, width: 120,),
),
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12))
),
),
SizedBox(height: 24,),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(this.titulo, style: TextStyle(fontSize: 20, color: Colors.white, fontWeight: FontWeight.bold),),
),
SizedBox(height: 8,),
Padding(
padding: const EdgeInsets.only(right: 16, left: 16),
child: Text(this.texto, style: TextStyle(fontSize: 18,color: Colors.white), textAlign: TextAlign.center,),
),
SizedBox(height: 24,),
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
FlatButton(onPressed: (){
Navigator.of(context).pop();
}, child: Text(this.cancelar),textColor: Colors.white,),
SizedBox(width: 8,),
RaisedButton(onPressed: (){
return Navigator.of(context).pop(true);
this.funcion();
}, child: Text(this.aceptar), color: Colors.white, textColor: Colors.redAccent,)
],
)
],
),
);
}
My issue is that the line of code that should include the function to be posted to the dialog widget :
funcion: SeguidoresCrud().dejarDeSeguir(documentIdSeguidores),
is marked as warning in the editor, the warning message says: Convert to an if element
I guess I am not doing it well, I mean, what I need is to pass a function as parameter to another widget, if possible...
The problem is that you're calling the function, not passing it
Change to:
funcion: () => SeguidoresCrud().dejarDeSeguir(documentIdSeguidores),
This happens because when you pass the function using (), you're actually calling the function and passing it's return value as an argument not the function itself to be called elsewhere
Pass function with () invoking operator
funcion: (){
SeguidoresCrud().dejarDeSeguir(documentIdSeguidores);
},

Flutter How Can I Show Dialog on Another Page

I want to show dialog when I press the button I want to be navigated to another page and then I want to show a dialog indicating that I have been navigated to that page.
So I try this code;
InkWell(
onTap: () async {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) => BottomBarD()),
(route) => false);
Dialog(
child: Container(
child: Column(
children: [
Text(
"Navigated to Another Page",
style: TextStyle(
fontFamily: "Quando",
fontWeight: FontWeight.w500,
fontSize: 15,
),
),
TextButton(
onPressed: () async {
Navigator.of(context).pop();
},
child: Text(
"Okey",
style: TextStyle(
fontFamily: "Quando",
fontSize: 15,
),
),
),
],
),
),
);
},
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.orangeAccent, Colors.red],
begin: Alignment.bottomRight,
end: Alignment.centerLeft),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(112.0),
topLeft: Radius.circular(112.0),
bottomRight: Radius.circular(112.0),
topRight: Radius.circular(112.0),
),
),
height: MediaQuery.of(context).size.height * 0.065,
width: MediaQuery.of(context).size.width * 0.80,
margin: EdgeInsets.only(
top: 30.0,
bottom: 10.0,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: Text(
"Navigate and ShowDialog Button",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 17,
fontFamily: "Quando"),
),
),
],
),
),
),
But when I press the okay button in the dialog, the okay button does not work and it gives a that error;
Unhandled Exception: Null check operator used on a null value
This worked fine on DartPad:
void _incrementCounter() {
Navigator.of(context).push(MaterialPageRoute(
builder: (c) => Scaffold(body: Text('new page'))
));
showDialog(context: context,
builder: (c) => AlertDialog(content: Text('the dialog in it'),)
);
}
Notice that .push() returns a Future immediately. The dialog you show after that is shown on top of page 2, since we don't await for it.
I put the Dialog in my second page BottomBarD() and I displayed it based on a conditional field every time the BottomBarD() loads.

How to create a custom Dialog in flutter

I want to create a custom dialog as shown below. I am able to create a normal dialog with two buttons(the positive and negative buttons). But I searched a lot about creating custom dialog like the one shown below but in vain.
showAlertDialog(BuildContext context) {
// set up the buttons
Widget cancelButton = FlatButton(
child: Text("Cancel"),
onPressed: () {},
);
Widget continueButton = FlatButton(
child: Text("Continue"),
onPressed: () {},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text("Action"),
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;
},
);
}
Now I want to have these buttons and the image as the children of the dialog and the icon button 'X' in the bottom to close the dialog. Any help is appreciated. I am a complete beginner in flutter.
For it, we create a custom dialog
1. Custom Dialog Content class
class CustomDialog extends StatelessWidget {
dialogContent(BuildContext context) {
return Container(
decoration: new BoxDecoration(
color: Colors.white,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.black26,
blurRadius: 10.0,
offset: const Offset(0.0, 10.0),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min, // To make the card compact
children: <Widget>[
Image.asset('assets/images/image.jpg', height: 100),
Text(
"Text 1",
style: TextStyle(
fontSize: 24.0,
fontWeight: FontWeight.w700,
),
),
SizedBox(height: 16.0),
Text(
"Text 1",
style: TextStyle(
fontSize: 24.0,
fontWeight: FontWeight.w700,
),
),
SizedBox(height: 24.0),
Align(
alignment: Alignment.bottomCenter,
child: Icon(Icons.cancel),
),
],
),
);
}
#override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
elevation: 0.0,
backgroundColor: Colors.transparent,
child: dialogContent(context),
);
}
}
2. Call Custom Dialog on Click:
RaisedButton(
color: Colors.redAccent,
textColor: Colors.white,
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return CustomDialog();
});
;
},
child: Text("PressMe"),
),