8.1 导航栏编写

8.1 导航栏编写

布局

image-20220718133430698

实现步骤:


第 1 步:i18n 多语言

lib/common/i18n/locale_keys.dart

1
2
3
4
5
// APP 主导航
static const tabBarHome = 'tab_bar_home';
static const tabBarCart = 'tab_bar_cart';
static const tabBarMessage = 'tab_bar_message';
static const tabBarProfile = 'tab_bar_profile';

lib/common/i18n/locales/locale_en.dart

1
2
3
4
5
// APP 导航
LocaleKeys.tabBarHome: 'Home',
LocaleKeys.tabBarCart: 'Cart',
LocaleKeys.tabBarMessage: 'Message',
LocaleKeys.tabBarProfile: 'Profile',

lib/common/i18n/locales/locale_zh.dart

1
2
3
4
5
// APP 导航
LocaleKeys.tabBarHome: '首页',
LocaleKeys.tabBarCart: '购物车',
LocaleKeys.tabBarMessage: '消息',
LocaleKeys.tabBarProfile: '我的',

第 2 步:BuildNavigation 导航栏封装

作为主界面的子组件,我们放在 /main/widgets 下面

lib/pages/system/main/widgets/navigation.dart

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import 'package:flutter/material.dart';
import 'package:flutter_woo_commerce_getx_learn/common/index.dart';
import 'package:get/get.dart';

/// 导航栏数据模型
class NavigationItemModel {
final String label;
final String icon;
final int count;

NavigationItemModel({
required this.label,
required this.icon,
this.count = 0,
});
}

/// 导航栏
class BuildNavigation extends StatelessWidget {
final int currentIndex;
final List<NavigationItemModel> items;
final Function(int) onTap;

const BuildNavigation({
Key? key,
required this.currentIndex,
required this.items,
required this.onTap,
}) : super(key: key);

@override
Widget build(BuildContext context) {
var ws = <Widget>[];
for (var i = 0; i < items.length; i++) {
var color = (i == currentIndex) ? AppColors.primary : null;
var item = items[i];
ws.add(
<Widget>[
// 图标
IconWidget.svg(
item.icon,
size: 20,
color: color,
badgeString: item.count > 0 ? item.count.toString() : null,
).paddingBottom(2),
// 文字
TextWidget.body1(
item.label.tr,
color: color,
),
]
.toColumn(
mainAxisSize: MainAxisSize.min,
)
.onTap(() => onTap(i))
.expanded(),
);
}
return BottomAppBar(
color: AppColors.surface,
child: ws
.toRow(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
)
.height(kBottomNavigationBarHeight),
);
}
}

第 3 步:控制器

lib/pages/system/main/controller.dart

1
2
// 分页管理
final PageController pageController = PageController();
1
2
3
4
5
6
7
8
9
10
11
12
13
// 当前的 tab index
int currentIndex = 0;

// 导航栏切换
void onIndexChanged(int index) {
currentIndex = index;
update(['navigation']);
}

// 切换页面
void onJumpToPage(int page) {
pageController.jumpToPage(page);
}
1
2
3
4
5
6
@override
void onClose() {
super.onClose();
// 释放页控制器
pageController.dispose();
}

第 4 步:视图

需要 KeepAlive 保持用户会话状态所以,我们采用 StatefulWidget + GetBuilder

lib/pages/system/main/view.dart

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// 主视图
Widget _buildView() {
DateTime? _lastPressedAt;
return WillPopScope(
// 防止连续点击两次退出
onWillPop: () async {
if (_lastPressedAt == null ||
DateTime.now().difference(_lastPressedAt!) >
const Duration(seconds: 1)) {
_lastPressedAt = DateTime.now();
Loading.toast('Press again to exit');
return false;
}
await SystemChannels.platform.invokeMethod('SystemNavigator.pop');
return true;
},
child: Scaffold(
extendBody: true,
resizeToAvoidBottomInset: false,
// 导航栏
bottomNavigationBar: GetBuilder<MainController>(
id: 'navigation',
builder: (controller) {
return BuildNavigation(
currentIndex: controller.currentIndex,
items: [
NavigationItemModel(
label: LocaleKeys.tabBarHome.tr,
icon: AssetsSvgs.navHomeSvg,
),
NavigationItemModel(
label: LocaleKeys.tabBarCart.tr,
icon: AssetsSvgs.navCartSvg,
count: 3,
),
NavigationItemModel(
label: LocaleKeys.tabBarMessage.tr,
icon: AssetsSvgs.navMessageSvg,
count: 9,
),
NavigationItemModel(
label: LocaleKeys.tabBarProfile.tr,
icon: AssetsSvgs.navProfileSvg,
),
],
onTap: controller.onJumpToPage, // 切换tab事件
);
},
),
// 内容页
body: PageView(
physics: const NeverScrollableScrollPhysics(),
controller: controller.pageController,
onPageChanged: controller.onIndexChanged,
children: const [
// 加入空页面占位
Text("1"),
Text("2"),
Text("3"),
Text("4"),
],
),
),
);
}

编译下程序,看看能运行么,要养成这个习惯,而不是写了很多再运行

提交代码到 git