系列:《Flutter从入门到放弃》 开发环境:Mac os + Android Studio 注意:读完本篇文章你可能会对其中的代码部分困惑,为什么要这么写? 没关系,我们会在下一节详细剖析。本节会对您思考如何使用Flutter重构您现有的项目带来一点启示。
自从上回跑通了Hello World后,鲍勃对Flutter的信心大增啊。心里琢磨着能不能用Flutter实现公司现在正在做的APP的效果呢!说做就做,马上拿起电话打给弗拉德老师,刚好弗拉德老师晚上也有空,两人就约在街角的咖啡店打发时间了。
街角的咖啡店
鲍勃:“弗老师,我想尝试用Flutter实现我们公司APP的效果”
弗拉德:“嗯,给我看下要实现什么样的效果?”
鲍勃:“嗯,很简单。就是下面这样的:”
弗拉德:“UI挺简单的,我们一步步来吧。先从底部的导航栏开始做吧”
弗拉德:“你准备怎么做呢,现在有想法吗?”
鲍勃:“首先,我肯定要定义顶部每一个Tab的类TabItem.dart”
1class TabItem {
2 TabItem({this.tabName, this.tabId});
3
4 String tabName;//顶部Tab的名称
5 int tabId;//顶部Tab的ID,因为需要根据不同分类ID去获取不同的内容的
6}
弗拉德:“嗯!不错”
鲍勃:“接下来,我是需要一个能在底部切换Tab的这种控件。弗老师,Flutter有这种widget吗?”
弗拉德:”嗯,你的思路很正确。确实有这样的Widget“
弗拉德:”我们需要用到MaterialApp的BottomNavigationBar“
弗拉德:”我们先建5个显示tab内容的布局吧:comu.dart,fit.dart,sports.dart,discovery.dart,mine.dart“ 以fit.dart为例,其它类似:
1// 目前我们只做底部导航栏,先不考虑上面这些模块之间内容的区别,可以用同一个代替
2import 'package:flutter/material.dart';
3
4class Fit extends StatefulWidget {
5 @override
6 FitState createState() => new FitState();
7}
8
9class FitState extends State<Fit> {
10 @override
11 Widget build(BuildContext context) {
12 return new MaterialApp(
13 home: new Scaffold(
14 appBar: new AppBar(
15 title: new Text("健身"),
16 ),
17 body: new Center(
18 child: new Text('Hello fit'),
19 ),
20 ),
21 );
22 }
23}
弗拉德:“我们先把需要用到的资源放到我们的工程中,如下图所示:”
弗拉德:“然后我们看下入口main.dart,我们需要创建一个widget作为最外层的框架”
1// 首页
2class HomePage extends StatefulWidget {
3 @override
4 State<StatefulWidget> createState() {
5 return new HomePageState();
6 }
7}
8
9class HomePageState extends State<HomePage> {
10
11 int _selectedIndex = 0;// 用来表示当前选择的索引,默认选择首项
12 var images;// 存储图标
13 // 底部导航栏的文字
14 List<TabItem> tabs=[
15 TabItem(
16 tabName:'社群',
17 tabId:0,
18 ),
19 TabItem(
20 tabName:'健身',
21 tabId:1,
22 ),
23 TabItem(
24 tabName:'运动',
25 tabId:2,
26 ),
27 TabItem(
28 tabName:'发现',
29 tabId:3,
30 ),
31 TabItem(
32 tabName:'我',
33 tabId:4,
34 ),
35 ];
36
37 var _bodyList = [
38 new Comu(),
39 new Fit(),
40 new Sport(),
41 new Discovery(),
42 new Mine(),
43 ];
44 // 初始化底部展示图标的列表
45 void init() {
46 images = [
47 [getImage('images/tab_association_grey.png'), getImage('images/tab_association_yellow.png')],
48 [getImage('images/tab_training_grey.png'),getImage('images/tab_training_yellow.png')],
49 [getImage('images/tab_sport_grey.png'), getImage('images/tab_sport_yellow.png')],
50 [getImage('images/tab_discovery_grey.png'), getImage('images/tab_discovery_yellow.png')],
51 [getImage('images/tab_me_grey.png'), getImage('images/tab_me_yellow.png')],
52 ];
53 }
54
55
56 // 通过资源路径获取对应的Image
57 Image getImage(path) {
58 return new Image.asset(path, width:24.0, height: 24.0);
59 }
60
61 // 这里是在每一次切换底部Tab时动态的去更新是否展示选中的图标
62 Image getTabImage(int index) {
63 if(index == _selectedIndex) {
64 return images[index][1];
65 } else {
66 return images[index][0];
67 }
68 }
69
70 // 这里是设置底部文字的样式
71 Text getTabText(int index) {
72 return new Text(tabs[index].tabName,
73 style: new TextStyle(fontSize: 11.0, color: Color(0xff333333)),);
74 }
75
76 @override
77 Widget build(BuildContext context) {
78 init();
79 return new MaterialApp(
80 title: 'Welcome to Flutter',
81 home: new Scaffold(
82 body: _bodyList[_selectedIndex],
83 bottomNavigationBar: new BottomNavigationBar(
84 items: <BottomNavigationBarItem> [
85 new BottomNavigationBarItem(icon: getTabImage(0), title: getTabText(0)),
86 new BottomNavigationBarItem(icon: getTabImage(1), title: getTabText(1)),
87 new BottomNavigationBarItem(icon: getTabImage(2), title: getTabText(2)),
88 new BottomNavigationBarItem(icon: getTabImage(3), title: getTabText(3)),
89 new BottomNavigationBarItem(icon: getTabImage(4), title: getTabText(4))
90 ],
91 type: BottomNavigationBarType.fixed,
92 currentIndex: _selectedIndex,
93 iconSize: 24.0,
94 onTap: (index){
95 setState((){
96 _selectedIndex = index;
97 });
98 },),
99 ),
100 );
101 }
鲍勃:“StatefulWidget是啥啊?”
弗拉德:“你可以先简单理解为这种类型的widget可以通过状态的变化来更新你的UI,后面理论阶段会仔细讲的。”
鲍勃:“好吧”
弗拉德:“接下来我们将上面的widget设置为整个应用的根widget”
1// 入口
2void main() => runApp(new MyApp());
3
4class MyApp extends StatelessWidget {
5
6 @override
7 Widget build(BuildContext context) {
8 return new MaterialApp(
9 home: new HomePage(),
10 );
11 }
12}
弗拉德:“接下来我们跑一下,看效果吧”
鲍勃:“效果出来了,蛮不错的,调调颜色就可以了”
弗拉德:“今天就到这吧,下次有机会再聊了。拜拜!”
鲍勃:“好的,弗老师。拜拜!”
由于5分钟的时间限制,我们下期详细剖析本节所涉及的以下知识: