flutter / flutter

Flutter makes it easy and fast to build beautiful apps for mobile and beyond
https://flutter.dev
BSD 3-Clause "New" or "Revised" License
164.93k stars 27.17k forks source link

Provide a way to return data when user does cupertino backswipe #139432

Open tomaspodmanicky opened 9 months ago

tomaspodmanicky commented 9 months ago

Is there an existing issue for this?

Use case

Currently, the PopScope widget does not allow to implement iOS back swipe with returning data to previous page. As WillPopScope is depracated because this feature is coming to Android, it should be improved...

In my applications, I HAVE TO return data to previous page - sometimes dialog has to be used, but sometimes not (canPop is kinda OK), but I also want to use iOS back swipe, because it is really handy feature and users like it.

Proposal

PopScope widget should be able to return data to the previous page. Overwrite the Navigator.pop(), that is built in the widget, or something. And what would be the best - ability to invoke back swipe, but, after that, prompt the dialog, so user can click "Cancel" and stay on current page.

navaronbracke commented 9 months ago

There is an open PR for this at https://github.com/flutter/flutter/pull/139164

chunhtai commented 9 months ago

If i understand correctly, this is asking for a way to inject result when user backswipe. The linked pr does not solve the issue.

chunhtai commented 9 months ago

@tomaspodmanicky I think it is always impossible to inject the result even with willpopscope, or did I misunderstood something?

tomaspodmanicky commented 9 months ago

@chunhtai yes, currently, it is not possible with WillPopScope, but because there is new widget for that I think it is good to implement this funcionality. Currently if you want to return data from current screen to previous, you cant backswipe on iOS, and that sucks...

tomaspodmanicky commented 9 months ago

sometimes I need to use exit dialog - that means I have to use Navigator.pop and backswipe is not possible, but I think it would be nice to have this feature implemented

chunhtai commented 9 months ago

it is by design, if user backswipe, it means they want to abort the current workflow. In this case, the system do not want anything to change. It is the same as android back button. It is also why the route future is always T?, not just T.

If you do want to have some data persist after a route is popped, you can use some state management system.

tomaspodmanicky commented 9 months ago

abort? i mean it works everywhere and it does not feel like I want to abort something. I just want to go back. So there is no chance of this feature being implemented? How can I then solve it using state management? Can you send me some link, tutorial or just something?

tomaspodmanicky commented 9 months ago

my problem is, that I navigate at some route, change the data there and then swipe back to the listview, where I need to update the data without calling the API...

navaronbracke commented 9 months ago

Perhaps you could take the API sample as a starting point?

https://github.com/flutter/flutter/blob/master/examples/api/lib/widgets/pop_scope/pop_scope.0.dart

It includes a dialog example.

For the other case, you could try to set canPop to true and set the "value" in the onPopInvoked callback, using a state management solution. This way you can still get the value when the user did a backswipe.

tomaspodmanicky commented 9 months ago

What do you mean, by starting point? I need to somehow update the data in listview, and this way it is the fastest.

But this callback in popScope is called after the pop is executed, so how can I return the data?

maRci002 commented 9 months ago

Before the pop event, the framework could request a result, which would then be delegated to PopScope.

https://github.com/flutter/flutter/blob/b0366e0a3f089e15fd89c97604ab402fe26b724c/packages/flutter/lib/src/cupertino/route.dart#L761-L762

CommonVoice commented 8 months ago

body: PopScope( canPop: true, onPopInvoked: (didPop) async { if (didPop) { ref.read(someProvider.notifier).presettedFunction(data); } },

if you use App-wide state(ex. riverpod) instead of sending data through Navigator.pop(), you can use back-swipe while updating the data also.

justinmc commented 7 months ago

Is the code below what you have with WillPopScope, and you're trying to migrate that to PopScope?

Maybe we shouldn't support that out of the box with PopScope. It seems like when using showDialog, if the user dismisses by tapping the barrier, then null is returned as the route result. So that tells me that passing a value other than null in that kind of situation is going against the design of things.

I think I would lean towards finding another solution as others have suggested.

Repro code ```dart import 'package:flutter/material.dart'; void main() => runApp(const NavigatorPopHandlerApp()); class NavigatorPopHandlerApp extends StatelessWidget { const NavigatorPopHandlerApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( initialRoute: '/home', routes: { '/home': (BuildContext context) => const _HomePage(), '/two': (BuildContext context) => const _PageTwo(), }, ); } } class _HomePage extends StatefulWidget { const _HomePage(); @override State<_HomePage> createState() => _HomePageState(); } class _HomePageState extends State<_HomePage> { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('Page One'), TextButton( onPressed: () async { // Waiting for some result from page two. final String? result = await Navigator.of(context).pushNamed('/two') as String?; print('The result of Page Two is |$result|'); }, child: const Text('Next page'), ), ], ), ), ); } } class _PageTwo extends StatefulWidget { const _PageTwo(); @override State<_PageTwo> createState() => _PageTwoState(); } class _PageTwoState extends State<_PageTwo> { final TextEditingController _controller = TextEditingController(); @override Widget build(BuildContext context) { return Scaffold( body: WillPopScope( onWillPop: () async { // Catch any back navigation here and instead manually pop with a // result. Navigator.pop(context, _controller.text); return false; }, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('Page Two'), TextField( controller: _controller, decoration: const InputDecoration( labelText: 'Input something and then perform a back gesure.', ), ), ], ), ), ), ); } } ```
AceChen7 commented 6 months ago

any update about this part,i think when user use swipe back,the data return to previous is normal action.

hodfords-khai-mobile commented 5 months ago

same issue

justinmc commented 5 months ago

The PR mentioned above is almost ready to merge (https://github.com/flutter/flutter/pull/139164).

Edit: Sorry, looks like that PR doesn't solve this issue. See also https://github.com/flutter/flutter/issues/138624.

tomaspodmanicky commented 2 weeks ago

anything new about this?

chunhtai commented 2 weeks ago

We can make use of https://api.flutter.dev/flutter/widgets/Route/currentResult.html

currently the backswipe just call navigator.pop without a result

tomaspodmanicky commented 2 weeks ago

and where should i use that?

justinmc commented 2 weeks ago

I guess there would need to be framework changes. Something like we could get a result from the route here:

https://github.com/flutter/flutter/blob/055350f84a79b6d6c5ef64ece524d64c9916bb70/packages/flutter/lib/src/cupertino/route.dart#L230-L234

And then pass it through to the pop here:

https://github.com/flutter/flutter/blob/055350f84a79b6d6c5ef64ece524d64c9916bb70/packages/flutter/lib/src/cupertino/route.dart#L820