Introduction
纸上谈兵终觉浅,绝知此事要躬行。
catsao(音:cat骚),我撸的第一个Flutter Application Demo,目前阶段它主要仿造目前主流的新闻资讯类app布局,实现了简单的新闻浏览。我还要继续丰富它,让它越来越sao。
Points
- TabBar实现:
@override
Widget build(BuildContext context) {
final List<Text> tabTexts = <Text>[
new Text(
StringResources.TAB_TOP_CN,
style: new TextStyle(
fontSize: 20.0
)
),
new Text(
StringResources.TAB_SH_CN,
style: new TextStyle(
fontSize: 20.0
)
),
new Text(
StringResources.TAB_GN_CN,
style: new TextStyle(
fontSize: 20.0
)
),
new Text(
StringResources.TAB_GJ_CN,
style: new TextStyle(
fontSize: 20.0
)
),
new Text(
StringResources.TAB_YL_CN,
style: new TextStyle(
fontSize: 20.0
)
),
new Text(
StringResources.TAB_TY_CN,
style: new TextStyle(
fontSize: 20.0
)
),
new Text(
StringResources.TAB_JS_CN,
style: new TextStyle(
fontSize: 20.0
)
),
new Text(
StringResources.TAB_KJ_CN,
style: new TextStyle(
fontSize: 20.0
)
),
new Text(
StringResources.TAB_CJ_CN,
style: new TextStyle(
fontSize: 20.0
)
),
new Text(
StringResources.TAB_SS_CN,
style: new TextStyle(
fontSize: 20.0
)
)
];
final List<Tab> tabs = [];
for (int i = 0 ; i < tabTexts.length ; i++) {
tabs.add(
new Tab(
child: tabTexts[i],
)
);
}
return new DefaultTabController(
length: tabs.length,
child: new Scaffold(
appBar: new AppBar(
title: new Text(
widget.title
),
bottom: new TabBar(
isScrollable: true,
tabs: tabs,
),
),
body: new TabBarView(
children: tabTexts.map((Text tab) {
return new Center(
child: new NewsPage(
tabName: tab.data,
)
);
}).toList()
),
drawer: new DrawerPage(),
)
);
}
复制代码
主要通过DefaultTabController + TabBar + TabBarView三个Widget配合实现类似Android中ViewPager + Indicator的效果。
build方法返回的最外层是一个DefaultTabController Widget,正如它的名字那样,它是一个控制器,用来控制TabBar和TabBarView的联动。要在界面上绘制一个TabBar和其对应的内容页使用TabBar和TabBarView两个Widget来实现的。
通过配置Scaffold的appbar参数为界面添加一个标题栏,再配置AppBar的bottom参数为标题栏添加一个显示在其底部的Widget,在这里传递给bottom参数的是一个TabBar Widget,所以在标题栏下方会显示一个TabBar。TabBar的每个Tab默认是固定位置的,这里配置其isScrollable参数为true使其可滚动,tabs参数配置TabBar中的每个Tab Widget。
通过配置Scaffold的body参数为其添加主内容界面,这里的内容界面需要配合TabBar的切换而切换,所以配置一个TabBarView Widget。最终通过外层的DefaultTabController使得TabBar和TabBarView联动起来。
关于实现类似效果的更多详细信息可参阅DefaultTabController,TabBar,TabBarView。
- Drawer实现:
return new DefaultTabController(
length: tabs.length,
child: new Scaffold(
appBar: new AppBar(
title: new Text(
widget.title
),
bottom: new TabBar(
isScrollable: true,
tabs: tabs,
),
),
body: new TabBarView(
children: tabTexts.map((Text tab) {
return new Center(
child: new NewsPage(
tabName: tab.data,
)
);
}).toList()
),
drawer: new DrawerPage(),
)
);
复制代码
Drawer的实现也很简单,Flutter都已经封装好了,直接配置Scaffold的drawer参数来实现一个Drawer界面。
- 数据缓存:
利用shared_preferences和sqflite插件分别实现SharePreference和DB的数据本地缓存,在项目的pubspec.yaml中配置依赖的插件:
dependencies:
......
sqflite: "^0.8.3"
shared_preferences: "^0.4.0"
......
复制代码
然后就可以在使用的地方import相应的package来使用对应功能。
- Column问题
使用Column时会遇到一个there are children with non-zero flex but the vertical constraints are unbounded的异常,大致意思是说Column内部有flex值不为0的children,但是当前Column在垂直方向的高度约束是无限制的。 简单解释一下,Column的children默认flex值是0,可以理解为flex为0的组件占用的空间是静态的。当一个组件的flex值不为0时,意味着它会去占用父容器布局完其他flex为0的组件后剩下的空间,占用多少跟flex的值有关。这有点类似Android中LinearLayout的weight。所以这个异常的意思其实是说因为当前的Column的垂直方向的高度约束是没有任何限制的,此时内部如果有flex非0的children的话它无法确定父容器的剩余空间有多大。
当一个Column的children中有一个或多个Expanded或Flexible组件,并且这个Column嵌套在另一个Column或ListView的内部,就会遇到这个问题。
解决的思路其实就是检查为什么自己的Column此时在垂直方向的高度约束是无限制的,大部分情况下可能是由于当前Column嵌套在另一个Column或ListView等容器中导致的。
关于该问题的详细描述可以参阅官方文档。
Effect
由于聚合数据只有获取新闻列表的接口(也可能我没找到单条新闻详情的接口),所以目前点击新闻的跳转是直接用浏览器打开了其对应的url。另外聚合数据获取新闻列表的接口貌似也没有支持分页参数…我还升级了聚合数据的高级会员,略坑。
Todo
- 下拉刷新
- 增加不同频道Route
- 图片本地缓存
End
天气接口:和风天气。
新闻接口:聚合数据。
部分图标:Iconfont-阿里巴巴矢量图标库。
源码地址:Catsao
关于Flutter项目的编译和运行可以参考官方文档。