Flutter:带有嵌套导航的底部导航栏和更改选项卡时恢复根页面
Posted
技术标签:
【中文标题】Flutter:带有嵌套导航的底部导航栏和更改选项卡时恢复根页面【英文标题】:Flutter: Bottom Navigation bar with nested navigation and Restoring the Root page when tabs are changed 【发布时间】:2021-08-06 04:02:55 【问题描述】:我是 Flutter 开发的新手。而且我已经通过多个教程来了解底部导航栏。
我已经尝试过这些教程,但我无法达到我的要求。 我遵循的教程:
-
https://codewithandrea.com/articles/multiple-navigators-bottom-navigation-bar/
https://medium.com/flutter/getting-to-the-bottom-of-navigation-in-flutter-b3e440b9386
https://medium.com/@theboringdeveloper/common-bottom-navigation-bar-flutter-e3693305d2d
我个人喜欢第一个教程,因为有嵌套路由。
信息:
我有 3 个标签的底部导航:主页、日历、个人资料。
主页标签有一个屏幕:Screen2。 日历有一个屏幕:Screen3。 个人资料有一个屏幕:Screen4
问题:
我的底部导航栏保持屏幕状态(这很好)。
主屏幕有一个打开Screen2的按钮。当用户点击时,它会推动 Screen2。当用户单击日历(选项卡)时,用户会看到日历屏幕。现在,用户再次单击主页按钮(选项卡),用户看到 Screen2。因为它是那条路线(家)的一部分。他应该只看到主屏幕的位置。
我只想重置它。基本上主屏幕应该推送主屏幕并弹出主页的所有子项。切换标签时。
代码:
main.dart
class MyApp extends StatelessWidget
// This widget is the root of your application.
@override
Widget build(BuildContext context)
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MainScreen(),
);
main_screen.dart
class MainScreen extends StatefulWidget
MainScreen(Key key) : super(key: key);
@override
_MainScreenState createState() => _MainScreenState();
class _MainScreenState extends State<MainScreen>
int _selectedIndex = 0;
List<GlobalKey<NavigatorState>> _navigatorKeys = [
GlobalKey<NavigatorState>(),
GlobalKey<NavigatorState>(),
GlobalKey<NavigatorState>()
];
List<Widget> _widgetOptions = <Widget>[
HomePage(),
CalendarPage(),
ProfilePage(),
];
Map<String, WidgetBuilder> _routeBuilders(BuildContext context, int index)
return
'/': (context)
return [
HomePage(),
CalendarPage(),
ProfilePage(),
].elementAt(index);
,
;
Widget _buildOffstageNavigator(int index)
var routeBuilders = _routeBuilders(context, index);
return Offstage(
offstage: _selectedIndex != index,
child: Navigator(
key: _navigatorKeys[index],
onGenerateRoute: (routeSettings)
return MaterialPageRoute(
builder: (context) => routeBuilders[routeSettings.name](context),
);
,
),
);
@override
Widget build(BuildContext context)
return WillPopScope(
onWillPop: () async
final isFirstRouteInCurrentTab =
!await _navigatorKeys[_selectedIndex].currentState.maybePop();
// let system handle back button if we're on the first route
return isFirstRouteInCurrentTab;
,
child: Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: Stack(
children: [
_buildOffstageNavigator(0),
_buildOffstageNavigator(1),
_buildOffstageNavigator(2),
],
),
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedIndex,
showSelectedLabels: false,
showUnselectedLabels: false,
items: [
BottomNavigationBarItem(
icon: Icon(
Feather.home,
color: Colors.grey[300],
),
label: 'HOME',
activeIcon: Icon(
Feather.home,
color: Colors.purple[300],
),
),
BottomNavigationBarItem(
icon: Icon(
FontAwesome.calendar,
color: Colors.grey[300],
),
label: 'CALENDAR',
activeIcon: Icon(
FontAwesome.calendar,
color: Colors.purple[300],
),
),
BottomNavigationBarItem(
icon: Icon(
EvilIcons.user,
color: Colors.grey[300],
size: 36,
),
label: 'PROFILE',
activeIcon: Icon(
EvilIcons.user,
color: Colors.purple[300],
size: 36,
),
),
],
onTap: (index)
setState(()
_selectedIndex = index;
);
,
),
),
);
home_page.dart
class HomePage extends StatefulWidget
HomePage();
@override
_HomePageState createState() => _HomePageState();
class _HomePageState extends State<HomePage>
@override
Widget build(BuildContext context)
return Container(
color: Colors.lightBlueAccent,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
child: Text(
'Screen 1',
style: TextStyle(color: Colors.white, fontSize: 20),
),
margin: EdgeInsets.all(16),
),
FlatButton(
onPressed: ()
// Navigator.push(context, MaterialPageRoute(
// builder: (context) => Screen2()
// ));
Navigator.push(context, PageRouteBuilder(pageBuilder: (_,__,___) => Screen2()));
,
child: Text('Go to next screen'),
color: Colors.white,
),
],
));
calendar_page.dart
class CalendarPage extends StatefulWidget
CalendarPage(Key key) : super(key: key);
@override
_CalendarPageState createState() => _CalendarPageState();
class _CalendarPageState extends State<CalendarPage>
@override
Widget build(BuildContext context)
return Container(
color: Colors.red,
child: Center(
child: FlatButton(
onPressed: ()
Navigator.push(context, MaterialPageRoute(
builder: (context) => Screen3()
));
,
child: Text('Go to next screen'),
color: Colors.white,
),
),
);
如果有人能指出我的方向,我将不胜感激。提前致谢。
要求: 有选项卡,每个选项卡将各自的屏幕(ScreenX-> ScreenY-> ScreenN)。当切换选项卡时,它应该弹出标签的所有子项。我希望这可以理解(对不起,我的英语不好)。
我错过了什么?
【问题讨论】:
我被困在同一个问题上,并且涉猎无济于事。如果您很幸运并找到了解决方案,请分享,它将对我有所帮助:) 是的,我将通过 EOD 或明天 EOD 分享解决方案。如果我没有,请再次评论,以便我得到提醒 如果有帮助请告诉我 【参考方案1】:所以逻辑是如果我从主屏幕(选项卡)移到任何其他选项卡。我应该清除堆栈(不是指小部件)。
假设您正在学习第一个教程。
有 3 个选项卡。 首页、日历和个人资料。
现在我从主屏幕添加了“Screen2”。所以,现在我的 currentTab 是 “首页”。如果我点击 Calendar 选项卡,我 selectedTtab 是“Calendar”。
我会弹出当前选项卡中的所有内容,直到遇到第一条路线。完成后,我将设置状态。
代码:
void _selectTab(TabItem tabItem)
if (tabItem == _currentTab)
_navigatorKeys[tabItem]?.currentState?.popUntil((route) => route.isFirst);
else
//! Added logic to Pop everything from Home tab, if any other tab is clicked
if (_currentTab == TabItem.HOME)
_navigatorKeys[_currentTab]
?.currentState
?.popUntil((route) => route.isFirst);
setState(() => _currentTab = tabItem);
我从底部导航调用这个方法。
bottomNavigationBar: BottomNavigation(
currentTab: _currentTab,
onSelectTab: _selectTab,
),
希望这会有所帮助。让我知道这是否足够。
【讨论】:
抱歉回复慢,忙于庆祝活动。我将在周末对此进行测试并更新您,感谢您分享此解决方案。希望它有效? :) 嘿 Akshay,我终于可以开始编写代码并检查了。您的更改有助于管理非常棒的状态。但我的问题还有第二部分。如何退出持久选项卡视图方法?例如,从menu
屏幕到login
屏幕。以上是关于Flutter:带有嵌套导航的底部导航栏和更改选项卡时恢复根页面的主要内容,如果未能解决你的问题,请参考以下文章