今日的程序码 => GITHUB
我们在开发的时候常常会遇到几种情况
BottomNavigationBar
的 index
改变後,再改回来时,页面要记住最後离开时的画面BottomNavigationBar
的 index
时,画面都是同一个。BottomNavigationBar
显示在下方,有时候不需要。这边我来给大家看今天会用到的画面,
如果看不太懂这个在写什麽的话,可以参考 Day-3 Route设定 的教学文章
class RouteName {
/// 控制 BottomBar 的画面
static const String bottomBar = 'bottomBar';
/// index=2 会用到的画面,用来展示切换後画面会被记住
static const String home_page_1 = 'home_page_1';
static const String home_page_2 = 'home_page_2';
/// index=2 会用到的画面,用来展示,只要按到 bottomBar 的按钮,把上就会变成没有 bottomBar 的画面
static const String second_page = 'second_page';
/// index=2 会用到的画面,用来展示切换後画面不会被记住
static const String third_page_1 = 'third_page_1';
static const String third_page_2 = 'third_page_2';
static const String third_page_3 = 'third_page_3';
/// index == 3 aaa 单存一个画面,用来当作展示的跳板
/// 按到 bottomBar 的按钮时,会先有 bottomBar,跳页後变成,没有 B bottomBar 的画面
static const String aaa = 'aaa';
static const String bbb = 'bbb';
}
这是由上而下的树状图
|App
|---|SecondPage|----------------------------------------------------
|---|BottomBarRoutePage| |
|---|------------------|NavigatorHomePage |
|---|------------------|-----------------|HomePage1 |
|---|------------------|-----------------|HomePage2 |
|---|------------------|SizedBox(BottomBarRoutePage 会直接把他跳到 SecondPage)
|---|------------------|NavigatorThirdPage
|---|------------------|------------------|ThirdPage1
|---|------------------|------------------|ThirdPage2
|---|------------------|------------------|ThirdPage3
|---|------------------|AAA
|---|------------------|---|BBB
这边是用来控制 BottomBar 的,和上一篇 Flutter - BottomNavigationBar(上)Animation 有一点类似,
官方文件 Key
是 Widget
、Element
的识别符号。 只有当新的 Widget
的 Key
与当前 Element
中 Widget
的 Key
相同时,它才会被用来更新现有的 Element
。 Key
在具有相同父级的 Element
之间必须是唯一的。
widget
在 app
中的任何位置更改其 parent
而不丢失状态。例:不同的萤幕,显示相同的 widget
globalkey
唯一定义了某个 element
,它使你能够访问 element
相关的对象。例:不同的 widget
访问状态这边之所以需要 globalkey
是因为我需要将它传给下一个元件,使这个状态会被记住,这样下次回来的时候,就会是离开的时候的状态。
WillPopScope
是 Android 的後退键,可以用来控制他,这边 WillPopScope
的逻辑是,当我按下 WillPopScope
,会去用 mabyepop
的方式,如果可以 pop
的话就 pop
,不行的话就不做动作。
class BottomBarRoutePage extends StatefulWidget {
const BottomBarRoutePage({required this.pageIndex});
/// initialize page index
final int pageIndex;
@override
_BottomBarRoutePageState createState() => _BottomBarRoutePageState();
}
class _BottomBarRoutePageState extends State<BottomBarRoutePage> {
/// page index
late int _pageIndex;
/// GlobalKey of navigator
Map<int, GlobalKey> navigatorKeys = {
0: GlobalKey(),
1: GlobalKey(),
2: GlobalKey(),
3: GlobalKey(),
};
@override
void initState() {
_pageIndex = widget.pageIndex;
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: WillPopScope(
onWillPop: () async {
/// maybePop the current index context
return !await Navigator.maybePop(
navigatorKeys[_pageIndex]!.currentState!.context);
},
child: IndexedStack(
index: _pageIndex,
children: <Widget>[
NavigatorHomePage(navigatorKey: navigatorKeys[0]!),
SizedBox(), // 整个换页。不要底部的 bottomBar
NavigatorThirdPage(
// 这边是因为跳下一夜的时候不希望底下还有 bottomBar
navigatorKey: navigatorKeys[2]!),
AAA()
],
),
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
showSelectedLabels: false,
showUnselectedLabels: false,
selectedItemColor: Colors.red,
unselectedItemColor: Colors.black,
items: <BottomNavigationBarItem>[
/// when index = 0, after the page A is changed to page B, then changed the index to 1, and changed the index back to 0, the screen page will be B page,
/// And there will be bottomNavigationBar in the process
/// 在 index = 0 时,把A 画面跳到 B 画面後,把 index 改成 1,再把 index 改回 1,此时画面一会在 B 画面,并且在过程中都会有 bottomNavigationBar 存在
BottomNavigationBarItem(
icon: Icon(Icons.people_outline),
title: Text('c'),
),
/// When index = 1, after the page A is changed to screen B, there'll be no bottomNavigationBar under the B page,
/// and then back to the A page, there will be a bottomNavigationBar at the bottom of the A page
/// 在 index = 1 时,把整夜 bottomBar 切换成 A 画面跳到 B 画面後,B 画面的下方不会有 bottomNavigationBar,此时再跳回道 A 画面,A 画面下方会有 BottomBar
BottomNavigationBarItem(
icon: Icon(Icons.add_to_photos_rounded),
title: Text('b'),
),
/// after the page changed, index changed, will not remember the page when you left, and the page will be the same every time when you re-enter index = 2.
/// 跳页後,更换 index,并不会记住离开时的画面,每次重新进入 index = 2 时,画面都会一样。
BottomNavigationBarItem(
icon: Icon(Icons.access_alarm),
title: Text('b'),
),
/// normal behavior
/// 一般行为
BottomNavigationBarItem(
icon: Icon(Icons.settings),
title: Text('c'),
),
],
currentIndex: _pageIndex,
onTap: (index) {
setState(() {
// index 0 1 2 3
/// when index == 1 then change to another Widget.
/// index == 1 时,代表他从 bottom_bar_route_page 跳到 新的画面
if (index == 1) {
Navigator.pushNamedAndRemoveUntil(
context, RouteName.second_page, (route) => false);
} else if (index == 2) {
/// create a new GlobalKey, and the page will be the same every time when you re-enter
navigatorKeys[2] = GlobalKey();
_pageIndex = index;
} else {
_pageIndex = index;
}
});
},
),
);
}
}
这边他会包成一个 Navigator。
什麽事 Navigator 呢?
官网介绍,我的理解,他也是一个路由器。
这边我拿到 BottomBarRoutePage 的 Key,是为了让画面记住状态。
onGenerateRoute
= 告知我的路由器是哪个
initialRoute
= 告知 App 开启後第一个画面是什麽
class NavigatorHomePage extends StatelessWidget {
NavigatorHomePage({required this.navigatorKey});
final GlobalKey navigatorKey;
@override
Widget build(BuildContext context) {
return Navigator(
key: navigatorKey,
onGenerateRoute: (RouteSettings settings) =>
MyRouter.generateRoute(settings),
initialRoute: RouteName.home_page_1,
//initialRoute: RouteName.third_page_1, <- NavigatorThirdPage 就要把上面注解,这边不要注解
);
}
}
他的概念很像是我的 App 底下有一个『根(root)』路由器,然後 BottomNavigation
算是 App 底下的一个画面,在这个 BottomNavigation
底下还有两个路由器。
app
| - app(root) 的路由器
| bottomNavigation
| - - - - - - - -| NavigatorHomePage 的路由器
| - - - - - - - -| NavigatorThirdPage 的路由器
只要是在 bottomNavigation
的 index == NavigatorHomePage 的 index
画面的话(也就是现在 bottomNavigation 是显示 NavigatorHomePage 这一页),之後再 pushNamed 的时候会有一些特性
BottomNavigation
的 index
并不会变动BottomNavigation
BottomNavigation 的 index
变动後,再回来时,会记住最後离开时的页面是哪一个。如果想要跳页後,不会显示 BottomNavigationBar
的话,就
将 rootNavigator 设定为 true,代表他跳到 app 底下的 root route 的画面。
Navigator.of(context,rootNavigator: true).pushNamed(RouteName.third_page_3),
如果想要按下 bottomBar 的按钮时,就直接转换成没有 bottomBarItem 的画面的话,可以直接在 BottomNavigationBar 的 onTap : (index){}
里面做手脚,类似范例的这几行。
onTap: (index) {
setState(() {
if (index == 1) {
Navigator.pushNamedAndRemoveUntil(
context, RouteName.second_page, (route) => false);
}
});
},
<<: [Day-19] R语言 - 分群应用(一) k - prototype类别补值 - 下 ( Fill.NA with k - prototype in R.Studio )
>>: Day-04 Python 的 Gradient 计算
绘制自己铁人赛文章资料所构成的图表 最後一天就来做个本次文章系列的总结吧,我用puppteer爬取了...
这系列主要就是讲Amazon ECS Anywhere 所以先来看看阳春版怎麽建立出来 基础运行元件...
上一篇定义了IAM里面会看到的名词,今天我们来看一下AWS Console里面要怎麽建置IAM Us...
大型数字 ( 图形数字 ) 教学原文参考:大型数字 ( 图形数字 ) 如果要在 Scratch 3 ...
今天做点简单的事情,先把搜寻作者的部份给加进来。 Layout也跟昨天一样先多加一行: 基本上前置作...