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專案的編譯和執行可以參考官方文件。