解决CupertinoTabScaffold在安卓系统上返回键退出app的问题

flutter有一套iOS风格的组件,其名为Cupertino,其中底部导航栏的组件为CupertinoTabScaffold,但由于iPhone/iPad上没有系统级返回按键,该组件在开发时可能并没有测试过安卓上的返回按键,所以这造成了无论app当前处于哪个页面,只要按下安卓上的返回键,整个app都会退出的问题,下面是我的一些推测以及解决办法:

1. 原因推测(不一定准确)

底部导航栏中的每个tab都会默认生成一个独立的Navigator,但这些Navigator是“隐式”的,无法响应返回按钮,只有最外层主程序(注意不是首页/第一个tab页面)的Navigator是显式的,所以无论在哪按返回键,调用的都是最外层主程序的Navigator的pop方法,所以app会直接退出。

2. 解决方法:

  1. 将每个tab的Navigator显式的声明出来:

    1
    2
    3
    4
    5
    final foundationNavKey = GlobalKey<NavigatorState>();
    final qrCodeNavKey = GlobalKey<NavigatorState>();
    final myPageNavKey = GlobalKey<NavigatorState>();

    final navKeys = [foundationNavKey, qrCodeNavKey, myPageNavKey];
  2. 使用tabController获取当前在哪个tab中:

    1
    2
    3
    4
    5
    6
    final tabController = CupertinoTabController(initialIndex: 0);

    CupertinoTabScaffold(
    controller: tabController,
    ...
    )
  3. 拦截返回按键并实现功能:

    1
    2
    3
    4
    5
    WillPopScope(
    onWillPop: () async {
    return !await navKeys[tabController.index].currentState!.maybePop();
    },
    )

3. 完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class YLXBApp extends StatelessWidget {
final foundationNavKey = GlobalKey<NavigatorState>();
final qrCodeNavKey = GlobalKey<NavigatorState>();
final myPageNavKey = GlobalKey<NavigatorState>();

Widget build(BuildContext context) {
final tabController = CupertinoTabController(initialIndex: 0);
final navKeys = [foundationNavKey, qrCodeNavKey, myPageNavKey];
final pages = [Foundation(), QRCode(), MyPage()];
return CupertinoApp(
home: WillPopScope(
onWillPop: () async {
return !await navKeys[tabController.index].currentState!.maybePop();
},
child: CupertinoTabScaffold(
controller: tabController,
tabBar: CupertinoTabBar(
items: [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.building_2_fill),
label: '基金会',
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.qrcode),
label: '二维码',
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.person_circle),
label: '我的',
),
],
),
tabBuilder: (context, index) {
return CupertinoTabView(
navigatorKey: navKeys[index],
builder: (context) { return pages[index]; },
);
},
),
),
theme: CupertinoThemeData(
brightness: Brightness.light,
),
);
}
}