上篇文章Android開發者的Flutter入門(一)講解了用Flutter開發一個簡單的新聞app的大致流程以及主要功能的實現。其中略過了一些功能的實現細節。這篇文章會對這些細節作一些闡述。涉及到的有如下這些點:ios
閃屏頁web
自定義佈局json
下拉刷新bash
上拉加載更多網絡
使用Assetsapp
路由(頁面跳轉)less
內嵌WebViewasync
因爲啓動Flutter app的時候須要初始化Flutter。這個時間是比較長的。因此開發Flutter app的時候都須要加一個閃屏頁。給Android平臺上跑的Flutter app加閃屏頁實際上是和給一個正常的Android app加閃屏頁是同樣的。ide
首先在AndroidManifest.xml
中,函數
MainActivity
設置了一個Theme; 另外注意一下第二個紅框中的
meta-data
標籤。那段註釋的大概意思是說這個標籤是用來表示讓Flutter在啓動過程當中保持閃屏頁直到第一幀畫面被繪製出來。也就是說,閃屏頁的隱藏不須要咱們來處理了。
接下來看看這個LaunchTheme
:
drawable
改爲你本身的閃屏頁圖片也OK。
至於ios平臺的閃屏頁怎麼弄,能夠參考這裏。
咱們都知道,在Android中,若是系統提供的佈局控件不能知足咱們的需求,咱們會自定義佈局控件來實現。Flutter一樣的也提供自定義佈局控件的功能。在這個新聞app中,首頁的列表項顯示效果以下圖,這就是用自定義的佈局控件來實現的。
這個列表項整個背景是新聞圖片,而後在下方疊加標題和來源,文字部分會有個半透明的背景。代碼在news_item.dart
中。
class NewsItem extends StatelessWidget {
...
@override
Widget build(BuildContext context) {
...
return new InkWell(
onTap: enabled ? onTap : null,
onLongPress: enabled ? onLongPress : null,
child: Semantics(
selected: selected,
enabled: enabled,
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: 200.0, maxHeight: 200.0),
//這個是自定義Layout
child: CustomMultiChildLayout(
// 這個Delegate用來作實際的佈局
delegate: ItemLayoutDelegate(),
//用來作佈局的子控件們
children: children,
))),
);
}
}
複製代碼
CustomMultiChildLayout
就是來讓你作自定義佈局的控件,須要一個Delegate作參數,這個Delegate須要咱們本身實現。另外一個參數children是須要佈局的子控件。自定義佈局控件的子控件們都須要用一個LayoutId
的控件包起來。這也是Flutter一個比較有意思的地方,不少在Android中咱們當作屬性來用的東西,Flutter都會作成一個類來包裹,這也是形成UI代碼比較難看的一個緣由。
這裏的id通常用枚舉來表示,例如
enum _Block {
bg,
text,
}
複製代碼
bg表明新聞圖片,text表明新聞標題。那麼你傳給CustomMultiChildLayout
子控件列表須要是這樣的,每個都要用LayoutId包起來:
final List<Widget> children = <Widget>[];
children.add(LayoutId(
//頭圖的id
id: _Block.bg,
child: FadeInImage.assetNetwork(),
));
children.add(LayoutId(
// 標題的id
id: _Block.text,
child: Container()
));
複製代碼
最後咱們在看看實際佈局是怎麼作的,來看ItemLayoutDelegate
的代碼:
class ItemLayoutDelegate extends MultiChildLayoutDelegate {
@override
void performLayout(Size size) {
if (hasChild(_Block.bg)) {
layoutChild(_Block.bg, new BoxConstraints.tight(size));
positionChild(_Block.bg, Offset.zero);
}
if (hasChild(_Block.text)) {
layoutChild(_Block.text,
new BoxConstraints.tight(Size(size.width, size.height * 0.4)));
positionChild(
_Block.text, new Offset(0.0, size.height - size.height * 0.4));
}
}
@override
bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) => false;
}
複製代碼
自定義的佈局是在performLayout
這個函數中進行的。入參是個Size
,也就是父控件的寬高。函數體就是根據id來取子控件,不一樣的子控件先調用layoutChild
給約束,再調用positionChild
擺位置,自定義佈局就完成了,是否是很簡單?
添加一個Material design風格的下拉刷新比較簡單,直接給列表包一個RefreshIndicator
就能夠了
return RefreshIndicator(
//觸發的回調
onRefresh: _onRefresh,
child: ListView.builder()
)
複製代碼
下拉刷新觸發的回調經過onRefresh
參數設置。在_onRefesh裏實現刷新數據的邏輯,須要注意的是函數_onRefresh須要返回Null類型的Future。在這個Future complete以後。刷新的圖標會本身消失。效果如圖:
Flutter沒有系統提供的加載更過控件,這裏咱們想辦法作一個比較粗糙的實現。思路是在列表的末尾添加一個加載控件,當滑動到列表底部的時候觸發加載的操做。
ListView.builder(
//列表長度加1
itemCount: _articles.length + 1,
itemBuilder: (context, index) {
if (index == _articles.length) {
//若是是最後一個,返回加載更過控件
return LoadingFooter(
retry: () {
loadMore();
},
state: _footerStatus);
} else {
//返回正常列表項
return NewsItem();
}
},
//檢測列表滾動狀態
controller: _controller));
複製代碼
在建立列表的時候咱們給列表長度加1,當要獲取最後一項時返回加載更多的控件,同時還要經過controller
監測列表滾動狀態。這樣咱們就給列表加了個上拉加載更多的功能。效果如圖:
在Flutter中若是你有圖片等文件須要引入到app中,都須要使用Assets, 這個Assets的概念不一樣於Android中Assets的概念,某種意義上講, Flutter的Assets更像是Android中Resource。Flutter中添加的asset都須要在pubspec.yaml
中聲明。例如,我須要添加一張圖片做爲加載網絡圖片時候的佔位圖,只須要作以下聲明就能夠了。
flutter:
assets:
- images/news_cover.png
複製代碼
Android中的Resources咱們能夠給資源文件夾按照必定規律來命名,這樣系統能夠挑選最適合的資源,一樣的Flutter的Asset也能夠。下面的聲明就提供了3種不一樣分辨率的圖標。
.../my_icon.png
.../2.0x/my_icon.png
.../3.0x/my_icon.png
複製代碼
Flutter中訪問Assets很靈活,最基本的能夠用如下方式來訪問Assets:
import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;
Future<String> loadAsset() async {
return await rootBundle.loadString('assets/config.json');
}
複製代碼
可是不少控件也會提供更方便的方式,具體可參考這裏。
Android中咱們都是用startActivity或者第三方路由庫來作頁面跳轉,在Flutter中,使用內置的Navigator來作跳轉的。Navigator是一個棧,當須要打開新頁面的時候就調用Navigator.push,須要返回的時候就調用Navigator.pop,本文中的app當點擊新聞項的時候要跳轉另一個頁面打開新聞詳情。代碼以下:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => WebviewScaffold(),
)));
複製代碼
Flutter自己沒有支持內嵌WebView。咱們能夠用第三方插件庫flutter_webview_plugin來實現。
首先在pubspec.yaml裏引入這個庫:
dependencies:
flutter_webview_plugin: "^0.1.5"
複製代碼
使用的時候直接傳入url和appBar就能夠了
WebviewScaffold(
url: '${_articles[index].url}',
appBar:
AppBar(title: Text("News Detail")),
)
複製代碼
至此對於個人第一個Flutter app講解已經完畢,相信你們看了以後就會對開發Flutter app的一些基本的技術點都有了瞭解。我也是剛開始學習,文中可能會有錯漏之處,歡迎你們指正。整體感受來說,用Flutter開發app能夠體會到不少不一樣於Android 原生app開發的理念。對於咱們開闊本身的技術思想仍是有頗有價值的。要深刻理解Flutter開發的方方面面仍是要多讀代碼多實踐,後面的路還很長,可是會頗有趣。