Flutter - set result to return when the user navigates back - flutter

When calling Navigator.pop() a result can be passed to the previous screen. Is there a way to set the result so that if the user navigates back on their own the result is still returned to the previous page?
I could pass an object to the second page and then modify it so that the first page can check it when the second page returns, but I'd rather use the result returned from the Navigator as it's more readable.
Overriding the back button's tap detector as I've seen suggested elsewhere is not an acceptable solution because the user may navigate back in some other way such as swiping or pressing the Android back button.

Yes, you can pass data between screens both ways.
While popping back, send the data you wish to send like this from the second screen
RaisedButton(
onPressed: () {
// The Nope button returns "data" as the result.
Navigator.pop(context, 'data');
},
child: Text('Nope!'),
);
And catch the result in the your first screen like this
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondScreen()),
);
source
For the other concern where the user is able to go back to the previous screen by pressing the back button, you can wrap your second screen with WillPopScope widget and provide the onWillPop callback. This will override the popping of the second screen and execute the callback where you can define the value you wish to return from the second screen.
#override
Widget build(BuildContext context) {
return WillPopScope(
child: Scaffold(), // or your widget
onWillPop: () {
return Future.delayed(Duration(microseconds: 0), () {
return Navigator.pop(context, "return-data");
});
},
);
}

Yes, this is possible, when navigating to Screen B from Screen A, make the onTap() functionasynchronous and await the result from Screen B.
Check the code below: It works perfectly:
On Screen A, put this code:
onTap: () async {
// receive the data you are sending from screen B here
final result = await Navigator.push( context);
},
On Screen B, put this code:
onTap: (){
// pass the data you want to use in screen A as the second paramter
Navigator.pop(context,number);
},
I hope this helps

Related

Flutter pop best practice

I have the following flow Screen 1 -> Screen 2 -> Dialog (in a separate widget).
Screen 2 displays a dialog (Close? Yes or No). If someone presses Yes, I would like to return to the Screen 1, if they press No, just close the dialog and return to Screen 2. What I currently do is when Yes is tapped, I do Navigator.pop(context) twice. Is this a good practice? Is there a way to pass the context of Screen 2 to my dialog widget so I can pop that one directly?
Personally, I think it would be better to pass the response from the dialog back to the page, and let the page handle the rest.
You can do this:
//I'm using a raised button just to call the alert as an example...
RaisedButton(
child: Text('Press me'),
//This part here is the important part
onPressed: () async {
//You can return anything when you use Navigator.pop
//In this case I'm returning a bool indicating if the page should close or not.
//You have to await this because it depends on user input.
bool shouldPopResult = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
//The content of your dialog
actions: <Widget>[
// The value you pass here in Navigator.of(context).pop
// is the value that will be stored in shouldPopResult,
// so if "Yes" is pressed, true will return...
// and if "No", false is returned.
FlatButton(
child: Text('Yes'),
onPressed: () => Navigator.of(context).pop(true),
),
FlatButton(
child: Text('No'),
onPressed: () => Navigator.of(context).pop(false),
)
],
),
);
// This is for if the user dismisses the dialog without pressing a button
// In that case shouldPopResult would be null, so I'm setting it to false.
// You can prevent the user from dismissing the dialog
// setting barrierDismissible to false in the showDialog method.
if (shouldPopResult == null) shouldPopResult = false;
// And finally with the dialog already dismissed, you can decide
// to go back or not.
if (shouldPopResult) Navigator.of(context).pop();
});
As usual you can extract the dialog as a Widget, or extract the function that handles the dialog response altogether or anything else.
You can see the example of returning data from a page in the flutter documentation here.

Flutter: Send data back to specific list item

I am trying to send data to a specific list item on the screen.
The logic is that you click on the specific card in the list it opens a second screen with an input field (see images below). You then submit your input and it changes the value of that specific card on the first screen.
What is the best way to achieve this?
You can do it like this:
Instead of only pushing to another page, await for a return
final data = await Navigator.push(context,
MaterialPageRoute(builder: (context) => InputScreen()));
setState(()
myList.add(data); //do whatever you want with the return here
});
And in your InputScreen you do this:
Navigator.of(context).pop(data);
Also, if your user press the back button of their phone, it will return null, so you will need to handle that.
You can achieve this by doing the steps below:
1) In the onTap function of the card, await the result by adding the code below:
// on tap function of your card
onTap: () async {
// navigate to the second screen and wait for input user enters
final result = await Navigator.push(context
MaterialPageRoute(builder: (context) => SecondScreen()));
// call setstate to see your changes
setState(() {
// add the input to your list
myList.add(result);
);
},
1) In the onTap function of your submit button send back the result by adding the code below:
// ontap function of your submit button
onTap: () {
// value is what the user has inputted in the text field
Navigator.pop(context, value);
},

How to call a function to update a value after popping a screen in Flutter?

Screen 1: shows list of item with add button.
Screen 2: form to add a new item to the list.
Screen 2 >> Screen 1 - While calling navigator.pop() in screen 2, how to call method/setState (to update list) in screen 1?
Can anyone help me out?
I don't want to relaunch screen again. I just need to run a method to update my list after popping previous screen?
When you navigate from Screen 1 to Screen 2, you use the push method. The push method returns a Future object.
You can use the then method of Future to execute your code after Screen 2 was popped from the navigation stack.
Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) => Screen2(),
))
.then((value) {
// you can do what you need here
// setState etc.
});
You can use Provider or BLoc or you can await for the result when you push the page
You can do it like this :
// this method waits for the pop to be called
var data = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => LoginScreen()),
);
debugPrint(data);
// here the second argument is the data
Navigator.pop(context, "data"); // popped from LoginScreen().
output
data
Same method can also be done like below
// this method waits for the pop to be called
Navigator.push(
context,
MaterialPageRoute(builder: (context) => LoginScreen()),
).then((data){
// then will return value when the loginScreen's pop is called.
debugPrint(data);
});
Here is a good article to look into this
https://medium.com/flutter-community/flutter-push-pop-push-1bb718b13c31
Navigator.pop has a second argument called result.
You could then return the value that you need to the first page that will read it as the return value of Navigator.push

How can I control what is passed to Navigator.pop() when clicking outside of a showModalBottomSheet?

I launch a modal bottom sheet, then use the data that is returned as its future.
var modalFuture = showModalBottomSheet(
// ...
);
modalFuture.then((data) {
// Use data
});
I return data to it from the modal widget with:
Navigator.pop(context, data);
This is working well when completing the modal interaction with a widget I've set up.
I encounter my issue when clicking outside of the modal. Clicking outside of the modal causes the modal to dismiss automatically (with a Navigator.pop(context) call?). I am okay with this closing interaction, but I would like to send data back with it (with a Navigator.pop(context, data) call). Is there anyway to override the implicit pop when clicking outside of a showModalBottomSheet modal?
You can wrap your ModalWidget with WillPopScope. You can see the example below
WillPopScope(
onWillPop: () async {
Navigator.pop(context, data);
return true; // return true if needs to be popped
},
child: ModelWidget(
…
),
);
This will ensure that Navigator.pop is called when auto popped using the back button.

In Flutter Which method gets called when pop back to Screen A from Screen B

I have updated my Sqlite Table in Screen B and want to reflect that change in Screen A Also.
So when Pop back from Screen B> Screen A nothing updated.
In Android, we have onResume() to make changes reflect in Activity A.
I have used Widgets Binding Observer but it works if app background, foreground.
Navigator.of(context).pop();
You can await Navigator.push, when pop is called anything below Navigator.push will be called. Ex:
await Navigator.push(SomePage());
/// This will be called after SomePage cals Navigator.pop();
doSomething();
You can get back from the second page with data like this:
// Second Page
Navigator.pop(context, 'result');
Then by the below code on the first page, you are able to lunch the second page and wait until return from it and get data.
// First Page
var result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondPage()),
);