Flutter:底部导航栏,带有嵌套导航和更改选项卡时恢复根页面



我是Flutter开发的新手。为了理解底部导航栏,我已经学习了多个教程。

我尝试过这些教程,但我无法达到我的要求。我遵循的教程:

  1. https://codewithandrea.com/articles/multiple-navigators-bottom-navigation-bar/
  2. https://medium.com/flutter/getting-to-the-bottom-of-navigation-in-flutter-b3e440b9386
  3. https://medium.com/@开孔显影剂/通用底部导航杆-搅拌器-e3693305d2d

我个人很喜欢第一个教程,因为里面有嵌套的路由。

信息:

我有3个选项卡的底部导航:主页,日历,个人资料。

主页选项卡有一个屏幕:屏幕2Calendar有一个屏幕:Screen3配置文件有一个屏幕:Screen4

问题

我的底部导航栏保持了屏幕的状态(这很好(。

主屏幕有一个按钮,可打开Screen2。当用户单击时,它会按下屏幕2。当用户点击日历(选项卡(时,用户会看到日历屏幕。现在,用户再次单击主页按钮(选项卡(,用户将看到屏幕2。因为那是回家路线的一部分。他应该只看到主屏幕的地方。

我只想重置它。基本上主屏幕应该推送主屏幕并弹出主页的所有子屏幕。切换选项卡时

代码:

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(),
);
}
}

主屏幕飞镖

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->Screen N(。当切换选项卡时,它应该弹出选项卡的所有子项。我希望这可以理解(对不起,我的英语不好(。

我在这里缺少什么

所以逻辑是如果我从主屏幕(选项卡(移到任何其他选项卡。我应该清除堆栈(不是指小部件(。

假设您正在学习第一个教程。

共有3个选项卡主页日历个人资料

现在,我在主屏幕上添加了">屏幕2";。所以,现在我的currentTab是">主页";。如果我单击日历选项卡,我选择的Ttab是">日历";。

我将弹出当前选项卡中的所有内容,直到满足第一条路线。一旦完成,我将设置状态。

代码:


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,
),

希望这能有所帮助。让我知道这是否足够。

最新更新