I am trying to use showDialog in the following manner
showDialog(context: context,child:new Text("Hello Dialgo"));
The above works fine however it states that child parameter has been deprecated and the alternative way is to :
'Instead of using the "child" argument, return the child from a
closure '
'provided to the "builder" argument. This will ensure that the BuildContext '
'is appropriate for widgets built in the dialog.'
I am not sure what that means. Any simple example here would be appreciated.
Change it it
showDialog(
context: context,
builder: (_) => new Text("Hello Dialgo")
);
If you need the context from within the dialog change builder: (_) => to builder: (BuildContext context) =>
Because the Builder is a function handler, we need to create a function which accepts a single argument (BuildContext) and returns a Widget.
Syntax can either be:
(BuildContext context) => new Text('...');
or
(BuildContext context) {
return new Text('...')
}
They are equivalent, though the second one can have more than one line
See an example here: https://github.com/aqwert/flutter_auth_starter/blob/master/lib/core/dialogs/showError_dialog.dart
The child deprecated. If you look the this property, you can this warning.
Instead of using the "child" argument, return the child from a closure provided to the "builder" argument. This will ensure that the BuildContext is appropriate for widgets built in the dialog.
If you want to use builder, only write a function that returns your widget.
Example usage in my loader function
void showLoader(BuildContext context) {
showDialog(context: context, builder: (BuildContext context) => new ProgressHUD(
color: Colors.white,
containerColor: Theme.of(context).primaryColor,
));
}
Usage
// Start to show loader
showLoader(context);
// Do a async job and wait it
await do();
// Hide the loader
Navigator.pop(context);
We can assign text widget to the alert variable, like this:
var alert = new Text("Hello dialog");
Since the child is deprecated:
showDialog(context: context, child: alert);
we can write it like this:
showDialog(context: context, builder: (_) => alert);
If you want to create more complex dialog, you can redefine alert like this:
var alert = new AlertDialog(
title: new Text('App'),
content: new Text(message),
actions: <Widget>[
new FlatButton(onPressed: () {Navigator.pop(context);},
child: new Text('OK'))
],
);
and use it the same as above.
This worked for me.
showDialog(
context: context,
builder: (BuildContext context) => new AlertDialog(
title: new Text('Warning'),
content: new Text('Hi this is Flutter Alert Dialog'),
actions: <Widget>[
new IconButton(
icon: new Icon(Icons.close),
onPressed: () {
Navigator.pop(context);
})
],
));
Related
The context:
I stumbled upon a minor crash while testing a ListView of Dismissibles in Flutter. When swiping a dismissible, a Dialog is shown using the confirmDismiss option, for confirmation. This all works well, however the UI crashes when testing an unlikely use case. On the page are several options to navigate to other (named) routes. When a dismissible is swiped, and during the animation an option to navigate to a new route is tapped, the crash happens.
How to replicate the crash:
Dismiss the Dismissible
During the animation that follows (the translation of the position of the dismissible), tap on an action that brings you to a
new route. The timeframe to do this is minimal, I've extended it in the example.
The new route loads and the UI freezes
For reference, this is the error message:
AnimationController.reverse() called after AnimationController.dispose()
The culprit is the animation that tries to reverse when it was already disposed:
package:flutter/…/widgets/dismissible.dart:449
Things I've tried:
Initially, I tried checking this.mounted inside the showDialog builder but quickly realised the problem is not situated there.
Another idea was to circumvent the problem by using CancelableOperation.fromFuture and then cancelling it in the dispose() method of the encompassing widget, but that was to no avail.
What can I do solve or at least circumvent this issue?
The code (can also be found and cloned here):
// (...)
class _DimissibleListState extends State<DimissibleList> {
int childSize = 3;
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: childSize,
itemBuilder: (context, index) {
if (index == 0) {
return _buildNextPageAction(context);
}
return _buildDismissible();
},
),
);
}
Widget _buildNextPageAction(context) {
return FlatButton(
child: Text("Go to a new page"),
onPressed: () => Navigator.of(context).pushNamed('/other'),
);
}
Dismissible _buildDismissible() {
GlobalKey key = GlobalKey();
return Dismissible(
key: key,
child: ListTile(
title: Container(
padding: const EdgeInsets.all(8.0),
color: Colors.red,
child: Text("A dismissible. Nice."),
),
),
confirmDismiss: (direction) async {
await Future.delayed(const Duration(milliseconds: 100), () {});
return showDialog(
context: context,
builder: (context) {
return Dialog(
child: FlatButton(
onPressed: () => Navigator.of(context).pop(true),
child: Text("Confirm dismiss?"),
),
);
},
);
},
resizeDuration: null,
onDismissed: (direction) => setState(() => childSize--),
);
}
}
I had almost same problem with confirmDismiss ,in my case I was using (await Navigator.push() ) inside of confirmDismiss to navigate to another screen but in return I faced this error :
AnimationController.reverse() called after
AnimationController.dispose()
so to solve my problem inside of confirmDismiss I call a future function out side of confirmDismiss (without await ) and then add return true or false after that function call to finish animation of confirmDismiss.
I am trying to make an API call using FutureBuilder in flutter but it seems like the request is not sent because I do not see the response printing. here is my future builder:
FutureBuilder(
future: authBloc.login(user, pass),
builder: (context, AsyncSnapshot snapshotItem) {
Map<String, dynamic> data = snapshotItem.data[0];
print(data['response']);
if (data.containsKey('id')) {
saveId(data['id']);
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (BuildContext context) {
return MainPage();
}));
}
if (data.containsKey("response")) {
if (data['response'] == false) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('An Error Has Occurred'),
content: Text(
'Please Make Sure That You Are Entering Valid UserName And Password'),
actions: <Widget>[
FlatButton(
child: Text("OK"),
onPressed: () =>
Navigator.of(context).pop(),
)
],
);
});
}
}
},
);
the authBloc.login(user, pass), part is login function in another file that makes the API call and I thought it is not necessary to include that file here.
Although I can't see the rest of your code, I think what you are trying to achieve should be done with an method and not a widget. When the user presses submit, call a function that basically contains what you wrote on that builder.
Calling navigator from within the builder is a bad idea. Any builder is expected to be called multiple times and in your case will lead to unexpected behaviour, that might be what you are seeing
I want user to select the option given in Radio Button before moving to second page in My Flutter Application. I'm showing Radio button widget inside Alertdialog it shows but radio button not changed after selecting.
Everything State Class
floatingActionButton: FloatingActionButton(
child: Icon(Icons.create),
onPressed: () {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text("Select Grade System and No of Subjects"),
actions: <Widget>[
Radio(value: 0, groupValue: groupValue, onChanged: selectRadio),
Radio(value: 1, groupValue: groupValue, onChanged: selectRadio),
],
));
},
),
selectRadio Function
void selectRadio(int value)
{
setState(() {
groupValue=value;
});
}
I had the same issue. I solved it by using this:
showDialog<void>(
context: context,
builder: (BuildContext context) {
int selectedRadio = 0;
return AlertDialog(
content: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Column(
mainAxisSize: MainAxisSize.min,
children: List<Widget>.generate(4, (int index) {
return Radio<int>(
value: index,
groupValue: selectedRadio,
onChanged: (int value) {
setState(() => selectedRadio = value);
},
);
}),
);
},
),
);
},
As I said the above comment showDialog creates new context and that setState on the calling widget therefore won't affect the dialog
You can create new stateful widget naming MyDialog.Checkout this gist such that you can get it(it uses dropdown but you can implement radio widget in same way).
custom language popup
You need to create separate statefulwidget class to handle state of radio button. Refer this example
how to execute a block of code when the user close Modal Bottom Sheet ?
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return new MusicR();
},
)
You can assign your showModalBottomSheet into a Future.
What will happen is that the user will trigger the close action on the modal sheet and trigger the then callback on your future variable.
Example:
Future<void> bottomSheetAwaitClose = showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container();
},
);
bottomSheetAwaitClose.then((void value) => print ("Bottom sheet closed"));
Code below prints 'null' after closing bottom sheet
test() async {
dynamic x = await showModalBottomSheet(context: context, builder: (context) => Container(height: 200.0, color: Colors.green,) );
print('$x');
// some other actions
}
I have problem with showDialog, when i press nothing happens but if i use Navigator.pushNamed(context, "/screen1") it works. I can not run Navigator.pop(context), it does not return any errors.
_showDialog(BuildContext context) {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text("Alert Dialog title"),
actions: <Widget>[
new FlatButton(
child: new Text("Back"),
onPressed: () {
//Navigator.pushNamed(context, "/screen1");
Navigator.pop(context);
},
),
],
);
});}
In my build() :
IconButton(
iconSize: 30.0,
onPressed: () => _showDialog(context),
icon: Icon(
Icons.clear,
color: Colors.white,
),
)
had the same issue .having useRootNavigator: false, in showDialog params solved my issue .
Use pop() two times:-
Navigator.of(context).pop();
Navigator.of(context).pop();
Reason: first pop function dismiss the dialog and Second pop function close the screen
The above answer should be accepted for this question, just elaborating the above answer
return showDialog(
context: context,
useRootNavigator: false, //this property needs to be added
builder: (BuildContext context) {....});
Try calling Navigator.of(context).pop(); instead of Navigator.pop(context);
For closing dialogs, you can also use:
Navigator.pop(context, true);
Source: https://docs.flutter.io/flutter/widgets/Navigator/pop.html
For those who have nested/multiple Navigators, you can also use the pop method as shown below (notice the named parameter rootNavigator set to true):
Navigator.of(context, rootNavigator: true).pop();
As suggested by others, I tried setting the useRootNavigator in the showDialog as false but this way the barrierColor wasn't covering the whole screen (it was only covering the screen displayed by Navigator object the dialog was in).
In summary, you can use the way showed above if you have nested navigators and want to achieve having the barrierColor covering the whole screen.