auto_route_library
auto_route_library copied to clipboard
How do I go back to the previous tab in the BottomNavigationBar?
I used the example (https://autoroute.vercel.app/advanced/bottom_navigation_bar_routing) and it works great except for one detail: if I go from the first tab to the second, and then press the "Back" button, then I exit the application, instead of going back to the previous tab. As far as I know, this behavior is not recommended and all popular applications return to the previous tab in such scenarios. How can I achieve this behavior so that when the back button is clicked, it will return to the previous tab in the bottom nav bar?
@moxajuine if you just want to exit the App if you're on HOME_TAB all you have to do is set
homeIndex: MY_HOME_TAB_INDEX
in AutoTabsRouter
or AutoTabsScaffold
@Milad-Akarie No, I do not want to exit the application. I am using AutoTabsScaffold and I have a bottom navigation bar with two tabs - the first tab and the second tab. When I switch from the first tab to the second, and then press the back button (being on the second tab) - I do not get back to the first tab. How can I make it return to the first tab?
@moxajuine alright but what happens if you're already on the first tab and you hit the backbutton?
@Milad-Akarie If I am on the first tab and press the back button, the application exits, as it should be. But the exit from the application occurs not only on the first tab, on the second tab the application will also exit. If you go to any popular application - for example youtube, go from the first tab to any other, and then press the back button, you will return to the previous tab instead of exiting the application. I would like to achieve the same behavior.
@moxajuine your goal is possible using navigation history, navigation history on mobile keeps the last 20 records ( hard coded for now ) a simple implementation would be
WillPopScope(
onWillPop: () {
final router = context.router;
if (router.canNavigateBack) {
router.navigateBack();
}
// if can't navigate back go with normal behavior
return SynchronousFuture(!router.canNavigateBack);
},
child: AutoTabsScaffold(...)
);
I just implemented this logic recently, and I don't think it's prefect yet, so if you spend some time on this and come up with good algorithm on when to reset or remove some history entires or if you need any simple Api changes/improvements let me know.
@Milad-Akarie
Thanks for the sample code.
I created a simple example with three tabs: first, second, third.
If, after launching the application, go to the second tab, and then to the third tab, then the first press of the button back will return us from the third tab to the second (as we expect), but the second press of the button back will exit the application instead of returning us to the first tab.
However, I found that if, after launching the application, we first go to the FirstDetailsPage page inside the first tab, and only then go to the second tab, and then to the third, then if we press the back button twice, we will return to the first tab. But now we will face another problem: returning to the first tab after having pressed the back button twice, we will see the FirstDetailsPage open in front of us (and this is correct, because we left it open before moving to other tabs), and if we press the back button, then FirstDetailsPage will close as it should, if we then press the back button again, nothing will happen, but if we press the back button a second time, then FirstDetailsPage will open again.
Perhaps I am doing something wrong or do not understand it well, so I would be grateful if you would look at my example. For the sake of simplicity, I've added everything to one file main.dart:
import 'package:auto_route/auto_route.dart';
import 'package:auto_route_example/routes.gr.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(App());
}
class App extends StatelessWidget {
App({Key? key}) : super(key: key);
final _appRouter = AppRouter();
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationParser: _appRouter.defaultRouteParser(),
routerDelegate: _appRouter.delegate(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
final router = context.router;
if (router.canNavigateBack) {
router.navigateBack();
}
return SynchronousFuture(!router.canNavigateBack);
},
child: AutoTabsScaffold(
routes: const [
FirstRouter(),
SecondRouter(),
ThirdRouter(),
],
bottomNavigationBuilder: (_, tabsRouter) {
return BottomNavigationBar(
currentIndex: tabsRouter.activeIndex,
onTap: tabsRouter.setActiveIndex,
items: const [
BottomNavigationBarItem(icon: Icon(Icons.dynamic_feed), label: 'First'),
BottomNavigationBarItem(icon: Icon(Icons.family_restroom), label: 'Second'),
BottomNavigationBarItem(icon: Icon(Icons.face), label: 'Third'),
],
);
},
),
);
}
}
// First Page
class FirstPage extends StatelessWidget {
const FirstPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("First Page", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
ElevatedButton(child: const Text("Go to First Details"), onPressed: () => context.pushRoute(FirstDetailsRoute(id: "some id"))),
],
),
),
);
}
}
class FirstDetailsPage extends StatelessWidget {
const FirstDetailsPage({Key? key, @PathParam("id") this.id = ""}) : super(key: key);
final String id;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("First Details Page, id = $id", style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
],
),
),
);
}
}
// Second page
class SecondPage extends StatelessWidget {
const SecondPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("Second Page", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
ElevatedButton(child: const Text("Go to Second Details"), onPressed: () => context.pushRoute(SecondDetailsRoute(id: "some id"))),
],
),
),
);
}
}
class SecondDetailsPage extends StatelessWidget {
const SecondDetailsPage({Key? key, @PathParam("id") this.id = ""}) : super(key: key);
final String id;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Second Details Page, id = $id", style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
ElevatedButton(child: const Text("Go to Second Details Info"), onPressed: () => context.pushRoute(const SecondDetailsInfoRoute())),
],
),
),
);
}
}
class SecondDetailsInfoPage extends StatelessWidget {
const SecondDetailsInfoPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text("Second Details Info Page", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
],
),
),
);
}
}
// Third Page
class ThirdPage extends StatelessWidget {
const ThirdPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("Third Page", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
ElevatedButton(child: const Text("Go to Third Details"), onPressed: () => context.pushRoute(ThirdDetailsRoute(id: "some id"))),
],
),
),
);
}
}
class ThirdDetailsPage extends StatelessWidget {
const ThirdDetailsPage({Key? key, @PathParam("id") this.id = ""}) : super(key: key);
final String id;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Third Details Page, id = $id", style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
],
),
),
);
}
}
And routes.dart:
@MaterialAutoRouter(
replaceInRouteName: 'Page,Route',
routes: <AutoRoute>[
AutoRoute(
path: "/",
name: "HomeRouter",
page: HomePage,
children: [
AutoRoute(
path: "first",
name: "FirstRouter",
page: EmptyRouterPage,
children: [
AutoRoute(path: '', page: FirstPage),
AutoRoute(path: ':id', page: FirstDetailsPage),
],
),
AutoRoute(
path: "second",
name: "SecondRouter",
page: EmptyRouterPage,
children: [
AutoRoute(path: '', page: SecondPage),
AutoRoute(path: ':id', page: SecondDetailsPage),
AutoRoute(path: 'info', page: SecondDetailsInfoPage),
],
),
AutoRoute(
path: "third",
name: "ThirdRouter",
page: EmptyRouterPage,
children: [
AutoRoute(path: '', page: ThirdPage),
AutoRoute(path: ':id', page: ThirdDetailsPage),
],
),
],
),
],
)
class $AppRouter {}
@Milad-Akarie : Any update on this? We have the same issue in our project. The route definition is not the same, but the structure is almost the same. After a little investigation here is what we have in the navigation stack after pushing a detail page(SpaceBrowserRoute) from a StackRouter under the TabRouter (RootNavigationRoute)
Sounds weird that we have the HomeRoute in the last position after pushing the Detail Page.
If the nesting after the transition is more than 2 routes, NavigationBack does not return to the previous tab.
I also note that sometimes ~ 1 out of 10 works ... it looks like a bug
I've also encountered weird behavior when navigating into a child route of a root route of the TabsRouter. Then occasionally when the navigationhistory has length 1 and I expect the app to close, instead it returns to a previously opened tab and it seems the history is reverted to an older state. For example one time the history entries were of length 3 after it was of length 1 before using navigateBack.
Im also facing this issue and i solve this by doing some changes in this code
WillPopScope(
onWillPop: () {
final router = context.router;
if (!router.canNavigateBack) {
router.navigateBack();
}
// if can't navigate back go with normal behavior
return SynchronousFuture(router.canNavigateBack);
},
child: AutoTabsScaffold(...)
);
just inverse not "!" condition
@moxajuine same behavior here. Did you find a solution for this? Thanks
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions
Still nothing?