前言
Flutter 從發(fā)布之日起我就對其心心念念了好久。
奈何這段時間實在是太忙了,加之自己拖延癥時不時發(fā)作下,一直都抽不出時間來學習這個跨平臺框架。
一轉(zhuǎn)眼 Flutter 1.2 都已經(jīng)發(fā)布了,這下實在是坐不住了。特地花了一周的時間來做了 一文 這個 APP 。以此來簡單了解下這款全新跨平臺框架的魅力。
第一個 APP
回到標題,既然是編寫第二個 Flutter APP,那就要求各位觀眾老爺自己對照著官方的 First Flutter APP 擼一遍。(中文鏈接:https://flutterchina.club/get-started/codelab/)
萬事開頭難,這部分包含了 dart 語言特性的學習,和 Flutter 框架一些特性的體驗。
如果你也是像我一樣只是花兩個小時簡單看了下 dart 語言的新特性就直接來擼第一個 APP。寫的時候可能會感覺總是在云里霧里,很多地方都不明白。
別擔心,這是正?,F(xiàn)象,對我們這種只想初步體驗的用戶來說,沒有系統(tǒng)的學習,這種情況才是正?,F(xiàn)象。
保持開放的心態(tài),多學多看。碰到不懂的,多查,碰到不知道怎么寫的,多看官方的源碼實現(xiàn),等代碼量上去了,自然就熟練了。
第二個 APP
照著官方示例完成了自己了的第一個 APP 編寫,是不是很有成就感?激動之余,似乎感覺少了點什么。
沒錯,畢竟只是照著官方的示例敲了一遍,說是 APP 也略簡陋了。是不是迫不及待的想做點什么來鞏固下自己的學習呢。
這次就跟著我一起從項目的立項開始你的第二個 APP 吧。
一文
由于項目一周的時間限制,本次就要求項目盡可能的簡單,頁面盡可能的少。且,要盡可能的完成多的功能點,于是 一文 就誕生了。
一文 是基于每日一文 API 開發(fā)的一款全新的 Flutter APP。
下載
https://github.com/chengww5217/one_article/releases
截圖
Highlights
- 這個項目足夠簡單
- 只有 splash、home、starred list 三個界面
- 這個項目功能點足夠多
- splah 頁面創(chuàng)建,去除啟動白屏
- 聯(lián)網(wǎng)、Json 解析、文章展示
- 數(shù)據(jù)庫保存文章
- 主題切換,字體調(diào)整,配置本地保存(SP)
- 國際化
- ···
- 這個項目還是有用的
- 和一般純練手 Demo 不同,每日一文是我每天都會看的
開始項目
注意:在源代碼中,一個頁面可能包含多個功能實現(xiàn),在實際做的時候,請依據(jù) APP 預覽一項一項進行實現(xiàn)。
源代碼并不是標準答案,有問題歡迎提交 PR 進行貢獻。
API
API 來源:https://github.com/jokermonn/-Api/blob/master/OneArticle.md
分析 API 進行聯(lián)網(wǎng)實現(xiàn),主要要求實現(xiàn)聯(lián)網(wǎng)獲取文章,獲取后進行 Json 解析到 bean,然后進行簡單的錯誤 handle。
參考文章:
Splash Page
按照原生 APP 開發(fā)的套路,用于初始化以及展示廣告的 Splash 是必不可少的。
第一個頁面,主要要求掌握頁面編寫的常規(guī)套路以及 StatefulWidget 的生命周期等。
比如 class SplashPage 的寫法:
class SplashPage extends StatefulWidget {
SplashPage({Key key, this.title}) : super(key: key);
final String title;
@override
State<StatefulWidget> createState() {
return _SplashPageState();
}
}
然后就是 class _SplashPageState 的編寫。
布局就是一張圖片:
import 'package:flutter/material.dart';
class SplashPage extends StatefulWidget {
SplashPage({Key key, this.title}) : super(key: key);
final String title;
@override
State<StatefulWidget> createState() {
return _SplashPageState();
}
}
class _SplashPageState extends State<SplashPage> {
@override
void initState() {
// TODO: do something to init
super.initState();
}
@override
Widget build(BuildContext context) {
return Builder(builder: (context) {
return Container(
child: Image(image: AssetImage('assets/images/splash.png'), fit: BoxFit.fill,),
);
});
}
}
生命周期如下:
圖片轉(zhuǎn)載自https://segmentfault.com/a/1190000015211309
具體 Splash 頁面講解參考我的博客:Flutter 開發(fā) Android & IOS 啟動頁 splash page
Home Page
主頁面主要是對文章進行展示以及相關(guān)設置項。
點擊左上角可以彈出相關(guān)配置彈窗。
考慮到布局的復雜度,這里可以將底部彈窗抽離出單獨寫進一個 .dart 文件。
從這部分就涉及到各個控件的使用和狀態(tài)設置,點擊事件等內(nèi)容。
這部分基本就是程序的核心內(nèi)容了。
完成了該部分之后就是對程序進行優(yōu)化,添加數(shù)據(jù)庫來緩存數(shù)據(jù),日期判斷切換,文章收藏等。
這個部分是耗時最長的,也是從磕磕碰碰到逐漸熟練的過程。
雜項
最后就是國際化,添加資源和打包等一些雜項了,具體參見
https://flutter.dev/docs/development/accessibility-and-localization/internationalization
https://flutter.dev/docs/deployment/android
結(jié)語
從剛開始看 dart 語法,到這個項目開發(fā)完成。斷斷續(xù)續(xù)一共持續(xù)了三周的時間。每天抽出一到兩個小時,合計一共是 56 小時左右。減去畫 APP 圖標,啟動頁面圖片的兩個小時,勉強算得上八小時工作制的一周。
這一周的使用過程中,F(xiàn)lutter 有些特性讓人感覺相見恨晚:語法特性(類型動態(tài)檢查,支持 .? ?? 操作符)、簡單方便完備的 UI 方案、Hot Reload等。但是諸如復雜冗長的 view tree、資源的硬編碼、糟糕的 UI 控件 API 等又讓人頭痛不已。
在初步使用 Flutter 之后,我發(fā)覺似乎 Flutter 短時間內(nèi)并不能讓我不學習原生開發(fā)就直接使用 Flutter 解決移動客戶端開發(fā)。
在不斷的使(zhe)用(teng)過程中,發(fā)現(xiàn)碰到好多問題還是需要你必須用原生開發(fā)的知識去解決相應的問題。 比如項目里面獲取已收藏文章,是這樣從數(shù)據(jù)庫里面獲取文件的:
Future<List<ArticleBean>> getStarred() async {
List<ArticleBean> articles = List();
Database db = await getDB();
List<Map<String, dynamic>> maps =
await db.query(name, columns: [columnId, columnStarred, columnDate, columnData], where: "$columnStarred = ?", whereArgs: [true]);
if (maps.length > 0) {
for (Map<String, dynamic> map in maps) {
ArticleBean article = ArticleBean.fromJson(map);
articles.add(article);
}
}
return articles;
}
請看核心查詢代碼
await db.query(name, columns: [columnId, columnStarred, columnDate, columnData], where: "$columnStarred = ?", whereArgs: [true]);
這里就是獲取所有 starred 為 true 的列。
但是實際運行的時候,發(fā)現(xiàn)在 Android 設備上面總是獲取不到。
Android 數(shù)據(jù)庫使用的是 Sqlite,不能存儲 bool(boolean)。相反,布爾值被存儲為整數(shù) 0(false)和 1(true)。
故上述代碼要改成下面的代碼才生效。
await db.query(name, columns: [columnId, columnStarred, columnDate, columnData], where: "$columnStarred > ?", whereArgs: [0]);
這只是一個很小的簡單例子,但是也說明了在 Flutter 上面并不能總是幫你解決原生的一些坑(這其實取決于各個框架的開發(fā)者為你做了多少兼容處理)。
本文到這里就要結(jié)束了,不怎么涉及具體代碼,只是一周時間的 Flutter 簡單上手。如果大家對項目有興趣,歡迎大家 star、fork 以及提交 PR,謝謝大家。