Closed JRamos29 closed 4 years ago
Hey @JRamos29, sorry for the delay, I've been under the weather lately. I don't believe your goal is doable using deep linking since pushing a deep link means pushing all the segments leading to your final destination ("/", "/page2","page_detail/:id") -> You're gonna need to pop all three pages to go back to /page1/page_list which can be confusing to users in my opinion.
You could try to create global keys for all of your nested navigators above your TabView widget
I'm thinking something like this
class HomeScreenState extends State<HomeScreen> {
final navigatorKeys = <String, GlobalKey>{
"tab1": GlobalKey<ExtendedNavigatorState>(),
"tab2": GlobalKey<ExtendedNavigatorState>(),
"tab3": GlobalKey<ExtendedNavigatorState>(),
};
// use this to access the navigators inside tabs not outside
static ExtendedNavigatorState navigatorOf(BuildContext context, String tabKey) {
return context.findAncestorStateOfType<HomeScreenState>()?.navigatorKeys[tabKey]?.currentState;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: TabBarView(
children: <Widget>[
ExtendedNavigator(
router: NestedRouter1(),
key: navigatorKeys['tab1'],
),
ExtendedNavigator(
router: NestedRouter2(),
key: navigatorKeys['tab2'],
),
ExtendedNavigator(
router: NestedRouter3(),
key: navigatorKeys['tab3'],
)
],
),
);
}
}
Hi Milad. Thanks for the answer and this great package.
I implemented my tabs as you said, and it's working. But when i try to push some route of another tab, i'm getting an error message saying that the navigator is null:
flutter: ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
flutter: The following NoSuchMethodError was thrown while handling a gesture:
flutter: The method 'pushNamed' was called on null.
flutter: Receiver: null
flutter: Tried calling: pushNamed<Object>("/post-detail")
Here is how i'm trying to push the route. I made just a little change in the map of keys using a enum instead of a string for the tabs:
import 'package:auto_route/auto_route.dart';
import 'package:auto_route_example/screens/home/bottom_bar_item.dart';
import 'package:auto_route_example/screens/home/home_page.dart';
import 'package:auto_route_example/screens/post/post_nested_router.gr.dart'
as postNestedRouter;
import 'package:auto_route_example/screens/post/post_nested_router.gr.dart';
import 'package:auto_route_example/screens/profile/profile_nested_router.gr.dart';
import 'profile_nested_router.gr.dart' as profileNestedRouter;
import 'package:flutter/material.dart';
class ProfileView extends StatelessWidget {
final String profileId;
ProfileView({this.profileId = 'default'});
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FlatButton(
child: Text("Profile View"),
onPressed: () {
HomePageState.navigatorOf(context, BottomBarItemType.POST)
.pushNamed(postNestedRouter.PostNestedRoutes.postDetail);
},
),
],
);
}
}
make sure you're using the passed context not the HomePage's context..rename it to ctx if you have to
static ExtendedNavigatorState navigatorOf(BuildContext ctx, String tabKey) {
return ctx.findAncestorStateOfType<HomeScreenState>()?.navigatorKeys[tabKey]?.currentState;
}
also make sure you're passing the keys to the navigators
ExtendedNavigator(
router: NestedRouter1(),
key: navigatorKeys['tab1'],
),
maybe you're calling the keys before they're initialized?
I'm initializing the keys and the nestedNavigator in the initState of my HomePageState. In the code above i'm trying to call a route from another tab. By example, Profile is a Tab and Post is another tab. I can do this?
Here is my HomePage:
import 'package:auto_route/auto_route.dart';
import 'package:auto_route_example/screens/activity/activity_nested_router.gr.dart';
import 'package:auto_route_example/screens/post/post_nested_router.gr.dart';
import 'package:auto_route_example/screens/profile/profile_nested_router.gr.dart';
import 'package:auto_route_example/screens/settings/settings_nested_router.gr.dart';
import 'package:flutter/material.dart';
import 'bottom_bar_item.dart';
class HomePage extends StatefulWidget {
final String title;
const HomePage({Key key, this.title = "Main Page"}) : super(key: key);
@override
HomePageState createState() => HomePageState();
}
class HomePageState extends State<HomePage> {
Map<BottomBarItemType, GlobalKey<NavigatorState>> _navigatorKeys;
// Map<BottomBarItemType, WidgetModule> _navigatorModules;
List _nestedNavigators;
BottomBarItemType _currentTab = BottomBarItemType.ACTIVITY;
int controllerIndex = 0;
initState() {
_navigatorKeys = {
BottomBarItemType.ACTIVITY: GlobalKey<ExtendedNavigatorState>(),
BottomBarItemType.POST: GlobalKey<ExtendedNavigatorState>(),
BottomBarItemType.PROFILE: GlobalKey<ExtendedNavigatorState>(),
BottomBarItemType.SETTINGS: GlobalKey<ExtendedNavigatorState>(),
};
_nestedNavigators = [
ExtendedNavigator(
router: ActivityNestedRouter(),
key: _navigatorKeys[BottomBarItemType.ACTIVITY],
),
ExtendedNavigator(
router: PostNestedRouter(),
key: _navigatorKeys[BottomBarItemType.POST],
),
ExtendedNavigator(
router: ProfileNestedRouter(),
key: _navigatorKeys[BottomBarItemType.PROFILE],
),
ExtendedNavigator(
router: SettingsNestedRouter(),
key: _navigatorKeys[BottomBarItemType.SETTINGS],
),
// HomeContentPage(),
];
super.initState();
}
// use this to access the navigators inside tabs not outside
static ExtendedNavigatorState navigatorOf(
BuildContext ctx, BottomBarItemType tabKey) {
return ctx
.findAncestorStateOfType<HomePageState>()
?._navigatorKeys[tabKey]
?.currentState;
}
void _selectTab(BottomBarItemType tabItem) {
setState(() => _currentTab = tabItem);
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
final isFirstRouteInCurrentTab =
!await _navigatorKeys[_currentTab].currentState.maybePop();
if (isFirstRouteInCurrentTab) {
// if not on the 'main' tab
if (_currentTab != BottomBarItemType.ACTIVITY) {
// select 'main' tab
_selectTab(BottomBarItemType.ACTIVITY);
// back button handled by app
return false;
}
}
// let system handle back button if we're on the first route
return isFirstRouteInCurrentTab;
},
child: Scaffold(
body: _nestedNavigators.elementAt(controllerIndex),
bottomNavigationBar: bottomNavigationBar(),
),
);
}
Widget bottomNavigationBar() {
return BottomNavigationBar(
backgroundColor: Colors.white,
showSelectedLabels: true,
type: BottomNavigationBarType.fixed,
items: [
_buildItem(item: BottomBarItem.fromType(BottomBarItemType.ACTIVITY)),
_buildItem(item: BottomBarItem.fromType(BottomBarItemType.POST)),
_buildItem(item: BottomBarItem.fromType(BottomBarItemType.PROFILE)),
_buildItem(item: BottomBarItem.fromType(BottomBarItemType.SETTINGS)),
],
onTap: (index) {
_selectTab(
BottomBarItemType.values[index],
);
controllerIndex = index;
});
}
BottomNavigationBarItem _buildItem({BottomBarItem item}) {
return BottomNavigationBarItem(
icon: Icon(
item.icon,
color: _colorTabMatching(item: item),
),
title: Text(
item.tabName,
style: TextStyle(
color: _colorTabMatching(item: item),
),
),
);
}
Color _colorTabMatching({BottomBarItem item}) {
return _currentTab == item.itemType ? item.tabColor : Colors.grey;
}
}
Everything looks fine actually can you debug this method and see if it's HomePageState that's null or the keys?
static ExtendedNavigatorState navigatorOf(
BuildContext ctx, BottomBarItemType tabKey) {
var homeState = ctx
.findAncestorStateOfType<HomePageState>()
print(homeState);
return homeState.
?._navigatorKeys[tabKey]
?.currentState;
}
The homeState and the Keys are ok. Just the currentState for the given key is returning null. It could be because i'm getting just one NestedRouter each time in the Scaffold's body like you can see in the code bellow?
When i press the bottom navigation bar, it get a specific router, which can let the others with state equals null, even if they are instantiated in the map on the initState?
Scaffold(
body: _nestedNavigators.elementAt(controllerIndex),
bottomNavigationBar: bottomNavigationBar(),
)
Hey @JRamos29 I've been working on publishing the new auto_route 0.6.0 lately so forgive my delay. I've created a demo app to demonstrate how you can implement parallel navigation using auto_route Parallel Navigation Demo hope this helps!
Hi @Milad-Akarie, Yes, that is a great example, mainly because the navigation from the Post tab to Profile tab, and without loss the bottom navigation bar. I really appreciated you help and attention. I believe you could add this example in the auto-route examples also, because there's many questions on stack overflow about how to do navigation in this way. I noticed that are a lot of new features in the 0.6.0 version. Congratulations for the great work. Tnks very much.
Hi @Milad-Akarie, ExtendedNavigator is not available in the new version of the package. Is there replacement for this widget?
Hi Milad, regarding the #66 question, I'd like to implement a BottomNavigationBar using AutoRoute, and I like to know what's would be a good approach, considering that i have some cases in which from a nested page from a bar item, i need to navigate to another nested page from other bar item. Can I navigate directly from a nested route to another, or I need to get the reference from a specific root navigator from each bar item?
I believe that feature its related to the #112 with deep link navigation, by example I'd like to navigate from /page1/page_list to /page2/page_detail/:id, or using a root router like /rootRouter/page1/page_list call /rootRouter/page2/page_detail/:id.
And it's possible to keep the nested navigation state? I mean, for a specific bottomNavigationBar page, when i go to a second page, click another bottomBar page, and then back to the previous item, i got the initial page and not the second page. There's some way to keep the page that i was before?