I have a function that displays a bottom sheet. If one item of this bottom sheet is selected it is dismissed using Navigator.of(context).pop() and a dialog is shown. If the user taps on the "Cancel" button I want to dismiss the dialog, too, so I tried using Navigator.of(context).pop() again. But nothing happens and I get the error message Looking up a deactivated widget's ancestor is unsafe. I tried deleting the first one and now the dialog can be dismissed by pressing "Cancel" button but the bottom sheet is still there. Ideally was a way to make the app in the current form work but dismissing both at the same time would also be fine.
I would really appreciate any help.
Edit: Added code
List<Widget> exerciseSelectionItems(BuildContext context, String schoolClassId) {
List<Widget> items = new List<Widget>();
for (var i = 0; i < selectableExercises.length; i++) {
Exercise currentExercise = selectableExercises[i];
items.add(
ListTile(
leading: Icon(currentExercise.icon),
title: Text(currentExercise.name),
onTap: () {
Navigator.of(context).pop();
showDialog(
context: context,
child: AlertDialog(
title: Text(
AppLocalizations.of(context).translate('create_homework'),
),
content: Text(
AppLocalizations.of(context)
.translate('create_homework_message'),
),
actions: <Widget>[
FlatButton(
child: Text('OK'),
onPressed: () {
Database().addHomework(
schoolClassId,
Homework(i, DateTime.now().millisecondsSinceEpoch),
);
Navigator.of(context).pop();
},
),
FlatButton(
child: Text(
AppLocalizations.of(context).translate('cancel'),
),
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
);
},
),
);
}
return items;}
Related
Okay guys, need your guidance, just started learning flutter (i am a java developer):
Imagine we have a simple list of ListTile widgets:
List testList = [
ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage(url
),
),
title: Text('Title text'),
subtitle: Text('Subtitle text'),
trailing: smth here also,
),
];
Imagine there are 1-2-3-n items in this array.
Now we want to display this list in a listview, seems quite simple:
children: <ListTile>[
for(ListTile e in testList)
e
],
Now we have all the elements.
Okay, now I want to add new list tile, and this is where I am stuck:
Let's add a dialog, which I am going to call every time the button is pressed:
TextEditingController txtController = TextEditingController();
Future<String> createTxtDialog(BuildContext context) {
return showDialog(context: context, builder: (context) {
return SimpleDialog(
title: Text("Input text"),
children: [
TextField(
controller: txtController,
),
MaterialButton(
elevation: 5.0,
child: Text('Submit'),
onPressed: () {
Navigator.of(context).pop(txtController.text.toString());
},
)
],
);
});
}
Okay, now let's call this function with our button:
// Here I want to add new item to my existing list and instantly get updated list:
// I will create a new list tile with only one row - this is going to be text received from our text controller:
floatingActionButton: FloatingActionButton(
onPressed: () {
createTxtDialog(context);
setState(() {
testList.add(
ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage(url
),
),
title: Text(txtController.text),
),
);
});
},),
So the problem is:
My list is updated normally, everything is okay, but I cannot see updated list until I reload my application.
I want to have my list updated "on the fly" - as soon as I add new item to the list - my new item is going to be displayed instantly
How can this be solved?
Thank you in advance! :)
P.S.
List updated, but with no text from the dialog
You can use initState and define your default testList in it.
initState({
// testList definition
});
After you add item to list, you can call setState.
The "OK" button on my alert dialog navigates to a new page. But when I go back to the previous page, the alert is still there. Is there any way for the alert to disappear after I navigate to the new page?
// Alert Dialog
Future<void> _handlePhoto(BuildContext context) {
return showDialog<void>(
context: context,
builder: (BuildContext context) {
return CupertinoAlertDialog(
title: Text('Please Position Crosshair'),
content: const Text(
'Before detecting cancer, ensure your focus area is centered.'),
actions: <Widget>[
FlatButton(
child: Text('OK'),
onPressed: () {
Navigator.of(context).pushNamed(
'/camerapage',
arguments: cameras,
);
},
),
],
);
},
);
}
Before pushing the new page, you need to pop the dialog like this. So when you come back it is not there.
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).pushNamed(
'/camerapage',
arguments: cameras,
);
}
I am showing a dialogue with Get library and I want to dismiss automatically after a few seconds with Future. But I found no suitable function for that. So how do I dismiss a get dialogue after showing it?
code:
Get.dialog(Center(
child: Material(
color: Colors.blue,
child: Text('Hello'),
),
)); // how to dismiss? Like Get.Dismiss().
for dismiss dialog try using :
Get.back();
or
navigator.pop();
I have not used Get, but if you really want to do that thing, that I can suggest my way of doing it.
So, we will be using Flutter AlerDialog Class, which works the same, that is popping up the dialog, and you can always edit the content.
Now let us do these things:
Creating a dialog
Pop Up when the button is clicked
Auto dismiss the dialog
This will help you organize your solution. And we will be using Future only.
showAlertDialog(BuildContext context) {
// set up the button
Widget okButton = FlatButton(
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;
},
);
}
This method will pop-up the dialog, and then autodismiss, the dialog:
void _ourAutoDismissDialog(BuildContext context){
//Calling out showdialog method
showAlertDialog(context);
//Auto dismissing after the 2 seconds
// You can set the time as per your requirements in Duration
// This will dismiss the dialog automatically after the time you
// have mentioned
Future.delayed(const Duration(seconds: 2), (){
Navigator.of(context).pop();
});
}
FlatButton(
onPressed: () => _ourAutoDismissDialog(context)
child: Text('Hello')
)
To dismiss the dialog, we need to do back operation, and we do it via Navigator.of(context).pop()
This is the result we get after implementing the above:
once i fill the form and submit it to Firebase,the code navigates me to my homepage but as soon as i press back button of my android phone, it send's user to previous form page with all previous filled data is available. i have tired using WillPopScope function to disable back button of my android phone but no response..
i have also created a function using willpopscope and called it in main but no result.
#override
Widget build(BuildContext context) {
return new WillPopScope(
onWillPop: () async =>false,
child: new Scaffold(
appBar: new AppBar(
title: new Text('Welcome'),
actions: <Widget>[
_onbackpressed(), //tried disabling the back button by calling this fucntion
new FlatButton(
child: new Text('Logout',
style: new TextStyle(fontSize: 17.0, color: Colors.white)),
onPressed: _signOut)
],
),
body: _showTodoList(),
floatingActionButton: FloatingActionButton(
onPressed: () {
signupPage(context);
},
tooltip: 'Increment',
child: Icon(Icons.add),
)
),
);
}
//extra funtion to disable the back button-
_onbackpressed(){
return new WillPopScope(
onWillPop: () async =>false,
child: new Container(width: 0.0,height: 0.0,),
);
}
//function used to send the user form to server
RaisedButton(
elevation: 7.0,
child: Text('Upload'),
textColor: Colors.white,
color: Colors.blue,
onPressed: () {
final StorageReference firebaseStorageRef =
FirebaseStorage.instance.ref().child(Username);
final StorageUploadTask task =
firebaseStorageRef.putFile(_image);
success(context);
},
),
//where success is a fuction
success(BuildContext context){
Navigator.of(context)
.push(MaterialPageRoute(builder:(context)=>Redirect() ));
}
Instead of pushing a new screen when the user submits the form, you should pop it, like this:
success(BuildContext context){
Navigator.of(context).pop();
}
The reason for this is because you have a stack of screens. When the user is done with one, you should send him back to where you want, instead of putting another one on the top and leaving the already used one on the stack.
I am experimenting with Flutter and having a problem with PopupMenuButton. After selecting an item in the menu I show a new screen without the menu, and after I navigate back the popup menu is still open - as shown in the following screenshots:
After navigating back from the edit profile screen (2nd screenshot) to the account screen (1st screenshot) the pop up menu is still open. I would like it to be closed. The relevant code where I create the popup menu inside an appbar:
actions: <Widget>[
new PopupMenuButton(
itemBuilder: (BuildContext context) {
return <PopupMenuEntry>[
new AppBarMenuItem("Edit profile", () => Navigator.pushNamed(context, Routes.editProfile)).build(context),
new AppBarMenuItem("Option 1", () => {}).build(context),
new AppBarMenuItem("Option 2", () => {}).build(context),
new AppBarMenuItem("Option 3", () => {}).build(context),
new AppBarMenuItem("Option 4", () => {}).build(context),
];
},
),
],
And the AppBarMenuItem:
new PopupMenuItem(
child: new InkWell(
child: new Text(_label),
onTap: _onTap,
)
How can I make sure that the popup menu gets closed after selecting an item? It looks like if I just use PopupMenuItem in my PopupMenuButton and navigate to the new screen in the onSelected function the menu closes properly. But when I use the onTap function of InkWell it doesn't close anymore.
Just use pop inside your onTap function Navigator.pop(context, "$popupValue");
PopupMenuItem<String>(
value: "Replay Game",
child: ListTile(
leading: Icon(Icons.replay,
color: theme.actionButtonColor),
title: Text("Replay Game"),
onTap: () {
Navigator.pop(context, "Replay Game");
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text("Clear input and replay game?"),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.pop(context),
child: Text("No"),
textColor: theme.alterDialogActionColor,
),
FlatButton(
onPressed: () {
store.dispatch(ReplayAction(timerBloc, varBloc.fireAnalytics));
Navigator.pop(context);
},
child: Text("Yes"),
textColor: theme.alterDialogActionColor,
),
],
);
});
},
),
)
as stated in the documentation the popup menu should automatically close when user selects an option from the popup menu item.
Using InkWell onTap wont automatically close the popup menu rather directly use the popup menu item to automatically close the popup menu when an item is selected from the popupMenuList
Make sure that the value property of the PopupMenuItem is not null otherwise the onSelected function will not be called when the PopupMenuItem is selected
I had this same issue and here is my solution. Your PopUpMenuButton() is not utilizing the onSelected property. The onSelected property will properly close your PopUpMenuButton. It currently is not because the onTap property of your AppBarMenuItem is taking over that job.
Also, I created a list of PopUpMenuItem, instead of PopUpMenuEntry, not sure if that makes a difference. But for each of my PopUpMenuItem, I also assigned the value property to each, so that the onSelected would communicate to the PopUpMenuButton() which item was tapped.
Something like this:
PopupMenuButton(
onSelected: (selection) {
switch (selection) {
case 1:
... do stuff...
break;
case 2:
... break stuff...
);
break;
}
},
Where case 1, case 2, etc refer to the value property I assigned to the PopUpMenuItem().