Return data from a screen on Flutter, without using Navigator.pop - flutter

I have a DetailPage that must return something to the code that called it. The documentation Return data from a screen explains that you must call Navigator.pop(context, whateverYouMustReturn) on some button.
So far so good, but what happens if the user clicks on the back button on the AppBar instead?? How do I return something then??
PS I'm using Navigator 1.0, btw

Provide your own leading widget and override the callback.
AppBar(
leading: BackButton(
onPressed: () {
Navigator.of(context).pop(myData);
},
),
),

Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: Container(), //Make leading an empty container to hide the default back button
),
body: WillPopScope(
onWillPop: () async {
Navigator.pop(context); //This method returns future boolean, based on your condition you can either
return true; //allow you to go back or you can show a toast and restrict in this page
},
child: Container(), //Your details page widget instead of container
),
);
}

Related

Flutter: How to change previous navigation route without actually navigating?

My users will navigate to screen 1, then screen 2 then screen 3.
When they click the back button on screen 3, depending upon a variable in that screen, I want the back button to either take them back to screen 2 or screen 1.
Note: the back button must be trigger by the user, I don't to pragmatically navigate back.
I thought I could use WillPopScope but that can only return a bool.
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
return true
},
child: Scaffold(
...
),
);
}
,
Here's an example:
return WillPopScope(
onWillPop: () async => true,
child: Scaffold(
appBar: AppBar(
automaticallyImplyLeading: true,
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
_user.isRegistered
? Navigator.popUntil(context, (route) => route.isFirst) // Takes the user to the first page
: Navigator.push(context, MaterialPageRoute(builder: (context) => SecondRoute()));
},
),

Is there any way to trigger onLongPress without user interaction?

GestureDetector(
onLongPress: (){
print("LONG PRESS");
},
child:Text("......")),
Now I want to trigger onLongPress without any user interaction.
Please give your valuable reply.
Here's how you can trigger any Gesture be it onTap , onLongPress or any other.
GestureDetector gestureDetector = GestureDetector(
onLongPress: () {
print('Long Press Called');
},
child: Text('Long Press'),
);
#override
Widget build(BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
gestureDetector.onLongPress();
});
return Scaffold(
appBar: AppBar(
title: Text('Flutter Gesture'),
),
body: Center(
child: gestureDetector,
),
);
}
Output :
I/flutter (19590): Long Press Called
In this code I'm calling onLongPress on addPostFrameCallback, which will be called after widgets are loaded. You can call gestureDetector.onLongPress() whenever you want to trigger onLongPress without user interaction.

Flutter testing WillPopScope with back button

On my Home widget, when user taps system back button, It shows by a WillPopScope a confirmation dialog widget.
I want to test this dialog but I cant figure it out how to press the back button on a test file.
I had the same problem but i had no back button in my app. I wanted to test the android system back button. This is how I did it. Maybe it's helpful for people who run into the same problem as me.
testWidgets("test onWillPop",(WidgetTester tester) async {
bool willPopCalled = false;
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: WillPopScope(
onWillPop: () async {
willPopCalled = true;
return false;
},
child: Container(),
),
),
),
);
final dynamic widgetsAppState = tester.state(find.byType(WidgetsApp));
await widgetsAppState.didPopRoute();
await tester.pump();
expect(willPopCalled, true);
});
Inspired by: https://github.com/flutter/flutter/blob/master/packages/flutter/test/material/will_pop_test.dart
I cant figure it out how to press the back button on a test file.
This will help you to see back button on appbar(top part of app). It will allow you to see back button via appbar
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
appBar: AppBar(
title: Text("Title"),
centerTitle: true,
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.black),
onPressed: () => _onWillPop(),
),
),
body: Body(),
),
);
_onWillPop will be your "confirmation dialog widget" for your question.
Apparently, you cannot access Navigator in the test. So my solution is to include BackButton somewhere in the pumped widget and to pop the page like this:
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: Container(
child: BackButton(),
),
),
));
...
await tester.pageBack();

What does MaterialPageRoute with the context?

What does MaterialPageRoute do with context?
And what is the purpose of builder: here.
MaterialPageRoute(builder: (context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
Every state of widget required some context to perform some work, direct or indirect context should be used.
The [BuildContext] for a particular widget can change location over time as the widget is moved around the tree. Because of this, values returned from
the methods in this class should not be cached beyond the execution of a
single synchronous function.
Example:
In the question code for back navigation used Navigator.pop(context); so it will be running in a separate state, not the build(contex) from where navigation starts

How to intercept back button in AppBar in flutter

I am using interceptor https://pub.dartlang.org/packages/back_button_interceptor to execute a method when the page 1 is back from page 2.
If I come back from page 2 to page 1 using device back button, the method is executed.
But if I come back from page 2 to page 1 using the arrow button at appBar I am not able to execute the method.
How can the back arrow button functionality default to the device back button?
You can surround your scaffold on Page 2 with WillPopScope, set onWillPop to false to prevent the page from being popped by the system and then add your own back button into the app bar's leading widget and perform your pop in there.
#override
Widget build(BuildContext context) {
return new WillPopScope(
onWillPop: () async => false,
child: new Scaffold(
appBar: new AppBar(
title: new Text("data"),
leading: new IconButton(
icon: new Icon(Icons.ac_unit),
onPressed: () => Navigator.of(context).pop(),
),
),
),
);
}
code for the answer from this post
Edit: Addition to Page 2 to control navigation
In addition to the above code you'll add the below code to page 2. Change
Navigator.of(context).pop()
to
Navigator.of(context).pop('upload_files')
Then in your page 1 where you navigate you'll await the navigation and use the result returned from the pop on page 2 and run your logic
var navigationResult = await Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => Page2()));
if(navigationResult == 'upload_files') {
uploadFiles(); // Perform your custom functionality here.
}
The default back button in AppBar is BackButton widget from material.dart. You may create it manually and pass your own onPressed to do what you want:
return Scaffold(
appBar: AppBar(
leading: BackButton(onPressed: _onBackPressed),
title: Text('Title'),
),
body: Container(),
);
If you do not specify leading in AppBar, then it creates a BackButton with the handler that does Navigator.maybePop(context).