-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pressing back via AppBar or System gesture pops to root on Android #176
Comments
Thanks for the issue and reproduction! And... welcome to the hell of Android back buttons. It's a world of confusion. Just to clarify definitions:
Routemaster's behaviour is, I believe, according to the Android docs, the "correct" behaviour on Android:
According to Google, within your app, the back and up buttons should always do the same thing. This is different to a web browser - the back button always navigates backwards through the stack of URLs, ignoring the app structure. So Routemaster's behaviour matches this, so the back button navigates upwards through the URL/page hierarchy, rather than what the user has actually seen (as on the web). But Google's guidelines on this have changed; they used to say that the system back button should follow your expected behaviour, and do something different to the up button. And some apps follow the old behaviour. Even Google's own Android apps have inconsistent back button behaviour. Soooooo yes... it's really confusing. I'm open to any suggestions to add options here, as long as they don't really overcomplicate the API. There are, however, already several ways you could override this, such as using |
Correct me if I'm wrong, but isn't that's exactly what @Maikuh is stating? That it is not following the behaviour according to the docs?
Under the "Actual Behavior" he states that navigating to the third screen and having second one in the "back stack", still pops to root |
Are there any updates on this one? Standard behaviour these days is for both the system back and app back button to behave the same, and just pop back one route. |
@josh-burton what do you mean by "pop back one route"? An upwards or reverse-chronological pop? |
reverse-chronological. |
I'm very much open to API proposals on this. However I feel like different developers will expect different behaviours on different platforms. This makes it pretty complicated. Just to define terms:
This is discussed on page 34 of the recent Flutter routing usability report. Currently the only reverse-chronological navigation with Routemaster is on web browsers, with the browser's back button. Any default app bar back button will use upward navigation. You can't currently do this on Android, but I'd like to enable it. Apparently I misunderstood the Android guidelines, and every back button should always be reverse-chronological. But this is surprising to me, and not how a lot of apps I've seen work, and against my expectations (but I'm not an Android user). But an interesting problem is the expected behaviour can differ between platforms. For instance, on iOS there's only ever "up" navigation. If the entire navigation stack is replaced, in general there's no way to return to the previous stack. So here are some questions we need to answer:
Also, if anyone has a good idea for a simpler term for "reverse-chronological", I'd love to know it 😁 |
Thanks for the great explanation. For me I think it makes sense for both iOS and Android to use up navigation by default. And the option to customise per platform, or for all platforms would be great as I'm sure there will developers who require it. |
This makes me sad, I've been loving Routemaster up to this point. |
I too was suddently perplexed when I found that the app bar back button was skipping the entire history and going back to the app root path. To quote OP:
I have only ever experienced the expected behavior (either when developing or as a consumer using apps) and I have never experienced what routemaster has implemented as actual behavior, where the stack is skipped. This includes flutter web on navigator 1.0, where the app bar back button works just like a browser back button. To skip back further, I've always just used popUntil I hit the named route. Question: Is there anyway to get the app bar back button to navigate in reverse chronological order, like the "expected behavior" op mentioned? Otherwise, how do you recommend one implement that sort of functionality. For example, I navigate users to page /third, and it's a dead end purposefully, using the back button is intentionally the only option to immediately go back to the previous screen. |
I want to follow up and provide a specific example, because I realize that what I want is possible... but it becomes a nightmare of origin management. ExampleMy apps are cross platform for web, ios, and android. So when I say back, I expect the browser back button, the app bar back button, and the android back button to function the same way (like they do on the twitter app / twitter web)
In that situation, the job page's route looks as follows: '/business': (_) => MaterialPage(child: BusinessDashboardScreen()),
'/job/:jobLogIndex': (route) =>
MaterialPage(child: JobDetailScreen(jobLogIndex: route.pathParameters['jobLogIndex'])), To fix this issue as routemaster currently works, I can change the job to a "relative" link.
In this situation, the routes look at follows: '/business': (_) => MaterialPage(child: BusinessDashboardScreen()),
'/business/job/:jobLogIndex': (route) =>
MaterialPage(child: JobDetailScreen(jobLogIndex: route.pathParameters['jobLogIndex'])), Foreseen ProblemThe problem I have with this is that I need to be able to get to the job screen from several different pages. So if this style of navigation only seems to work if I create relative job paths for every potential screen that can link to the jobs page. So if I have 5 screens that link to the jobs page, I need to create additional relative jobs routes in the RouteMap. If I want to get to the job screen from the "monitoring" screen, I have to create the route again with that prefix. '/monitoring': (_) => MaterialPage(child: MonitoringDashboardScreen()),
'/monitoring/job/:jobLogIndex': (route) =>
MaterialPage(child: JobDetailScreen(jobLogIndex: route.pathParameters['jobLogIndex'])),
'/business': (_) => MaterialPage(child: BusinessDashboardScreen()),
'/business/job/:jobLogIndex': (route) =>
MaterialPage(child: JobDetailScreen(jobLogIndex: route.pathParameters['jobLogIndex'])), As an app grows, this does not scale. Am I missing another solution or way of using this? |
on a tangent a bit but I have the same problem above with a detail screen being show from two different list screens. Additionally I am using In my situation I don't mind to define the routing twice as we can provide urls in emails consistent across web and mobile (deep links). If I am going further down into a sub screen I will 'push' otherwise 'replace'. If I have deep linked in I would expect back to exit the app not go up. If I navigate down a nested route then either push or replace would achieve the same thing, that feels weird too. |
@buzzware nooo! Let's make you happy again! Do you have any comments/ideas on my questions from above? @mdrideout thank you so much for the specific example, that's really useful. I'm thinking about the API for this. I don't think the actual coding here is that difficult, we can solve this together - it's just designing the API, making it flexible enough for everyone's needs but not making it overly complicated is quite a big challenge. I'll see if I can come up with a way you can work-around this until the functionality is in Routemaster. I totally get why this is a big issue and want to address it ASAP. Who would have thought something as simple as a back button is so complicated? 😁 |
Okay, I've done some thinking! Current thoughts are below. I'm prioritising this issue above anything else, I understand how important it is. I would massively appreciate feedback. Designing APIs alone is really hard 😁 API
ScenariosBack button reverse-chronological, but up button popsThis would be achievable by using the global Back button delegateThere should be a way to intercept the Android back button and make decisions based on app state. This could include going to some other route that isn't in the back stack at all. ComplicationsJust AndroidNone of this would affect web. Web is totally driven by the current URL, nothing else. This makes APIs potentially very confusing. I was totally confused by this at first with Flutter's But... I really don't want to add parameters like I think the only answer to this is clear documentation. TabsAnother thing - should reverse-chronological navigate back through tabs? For example:
Should the app switch back to tab one, or close (because there's nothing in the back stack)? Different Android apps do different things. This also feels like something that should be configurable? In summary... PLEASE HELP ME, BACK BUTTONS ARE MAKING ME CRAZY 😁😁😁 |
I think this sounds great.
Couple Questions
Name Parameter |
Yep, think I'm going to need to provide both options for tabs. I asked on Twitter what people thought the behaviour should be, and after 71 votes it's almost 50/50 😁
You'll be able to solve that wit this, by having
Yes, this could be added, but I think I'll leave it just for the moment to get the core right.
|
Working on this today. Everyone seems to have a different view on the "correct" Android back button behaviour: Nightmare. So the only option here is, well, providing options. And possibly lots of them. TabsI'm currently trying to come up with a good API for specifying Android back button behaviour with tabs. Initially I thought there were only two options:
But then it turns out React Navigation has five (!) different options. Which of these do you think it's useful to support? Would it make sense to add some sort of delegate handler to make decisions?
|
There are also so many different "situations" tabs are used that I think it should not be a global setting for all tabs, but specific to the instance of the tabs declared for a UI scenario. I'm not sure we need all of these to start with, but I think the 1 & 2 you originally identified are more important than all the options that React Navigation handles, which could be incorporated in the future if the architecture is there to support adding more options. Dev Scenarios
|
The Unbearable Lightness of the Android Back ButtonI started looking at what "big" (well some) apps do on Android on bottom nav or main nav pattern it uses, when using system back button or back swipe function. I had not though so much about it before, but gosh did I find a can of worms. 1. Always pops entire app, regardless of where you are on bottom destination
2. If not on 1st destination, goes to 1st, then pops app.When on 1st destination, these always pops the app, but only from 1st one.
I used this in an app, because I disliked 1 so much and this was simple to add. Just a, if not on 1, then move there if the app tries to pop itself, if on one, then fine go ahead pop app. 3. Keep unique visited destinations on a stack equal to nr of bottom destinations, pop back in last used unique order, when nothing left, if not on 1, then back to 1, then pop app
To mention a few. I rather like this one actually, but 2 is fine as well imo. 4. Keep N unique destinations, then pop the app.Usually N is equal to nr of bottom destination. Pop them until nothing remains, then pop app. The app can thus be popped from other than 1st destination, depends on how you navigated on bottom navbar
5. Keep entire bottom nav history.Just keep them all on a stack and pop back in order until nothing remains, then pop app. Since you started on 1, you eventually end up popping the app from 1.
Have you found any other patterns? Why use back button/swipe on Android with bottom navbars?Some claim they never navigate with the back button/swipe on Android in apps with bottom navbars. I do it all the time. Why? When I hold the phone with one handed grip with my right hand in the lower right corner, I can't reach the 1st destination with my thumb without using very uncomfortable and wobbly phone tilting action to reach it, so I just swipe back with my thumb to get there. I expect it to get to 1st destination at some point, like in cases 2, 3 and 5. If the app then does pattern 1) it is really the worst UX of them all. Hue that I use a lot makes me wanna scream in frustration. Case 4 is just weird, but you might not notice its weirdness unless you really look for it and create a back stack that shows it, but when it happens it is a bit of a WTF moment. |
Hello patient people! I've just done a new prerelease that I believe resolves the core of this issue: v0.10.0-dev4. It switches the default system back button behaviour on Android to reverse-chronological. I decided to make this a breaking change. Currently, there's no parameter to switch back to the old behaviour. I'm still thinking about the best way of doing this, and if it's needed. However you can override TabsTab pages default to not adding to the chronological history stack. This is also a breaking change, you can make them add to the history by setting This might not be the best default on Android... but then again I don't think there's any default that will please everyone 😁. I plan to add more tab history options, such as the ones Mike highlighted. HistoryThere is also a new history object, allowing you to navigate chronologically:
Adding I would love feedback and testing on these changes. There is a high chance of bugs, this has required some pretty major changes (40 changed files with 1,661 additions and 233 deletions!). Note that you must use at least the current Flutter stable 2.5 with the new version. |
Thanks for including this feature, it's very useful! I tried out 0.10.0-dev5 and strangely it seems to work opposite to how you described above. The default back behaviour was to go back to root, and any times I had used |
It works, you just need to add option for tabs and use history.back() instead of pop() I think, it would be nice to add this to docs. The feature is very useful. I have app for web, android and ios and expect same navigation behavior for all platforms. The only bug i faced is when i press back too quickly (by using android/appbar button or gestures) i get an error and navigation breaks. It happens when the history stack contains about 5 or more routes and i tap or swipe very quickly, as a regular user will never do. It was reproduced in android debug mode, i will check it on ios and release build later, then provide more details if you need updated: The bug was reproduced on release buld too. It's showing tab content of inactive tab, probably previous. Looks like getting params from previous route causing this error: |
Not directly related to the ongoing discussion, but looking forward to get proper |
I'm years late to this discussion... but still - Thank You! |
Expected Behavior
/
, push to/second
/second
, push to/third
/third
, pop goes to/second
/second
, pop goes to/
Actual Behavior
/
, push to/second
/second
, push to/third
/third
, pop goes to/
Notes
This doesn't happen if
/third
is relative to/second
, like/second/third
. Also, on the Web, going back via the Browser's back button has the expected behavior too. I have a feeling it has to do with https://github.com/tomgilder/routemaster/wiki/Routemaster-Flutter-scenarios#skipping-stacks But I couldn't see a way to disable that behavior.Minimal reproduction code
The text was updated successfully, but these errors were encountered: