上一篇我們實現了新聞列表,但在網絡不好的時候列表會白屏,因此爲了提高使用體驗,往列表中加入懶加載效果。其次,引入一個Flutter內置的手勢控件,用於支持下拉刷新列表的效果如下圖:
Flutter將異步執行也進行了控件化處理,即:Future。不過我還沒完全掌握怎麼使用Future,只能把學到的跟大家分享一下,以後玩6了再補充。前面的分享中大家應該也接觸並使用到了Future,比如IO操作的HTTP請求。除了通過async
和await
關鍵字以外,還可以用一個更方便的控件,可生成代碼在異步執行時間軸上的快照,並按照自己的需求觸發需要的事件,這就是FutureBuilder控件。
FutureBuilder用法和實現
先簡單講講FutureBuilder。
//FutureBuilder控件
new FutureBuilder<String>(
future: _calculation, // 用戶定義的需要異步執行的代碼,類型爲Future<String>或者null的變量或函數
builder: (BuildContext context, AsyncSnapshot<String> snapshot) { //snapshot就是_calculation在時間軸上執行過程的狀態快照
switch (snapshot.connectionState) {
case ConnectionState.none: return new Text('Press button to start'); //如果_calculation未執行則提示:請點擊開始
case ConnectionState.waiting: return new Text('Awaiting result...'); //如果_calculation正在執行則提示:加載中
default: //如果_calculation執行完畢
if (snapshot.hasError) //若_calculation執行出現異常
return new Text('Error: ${snapshot.error}');
else //若_calculation執行正常完成
return new Text('Result: ${snapshot.data}');
}
},
)
FutureBuilder通過子屬性future
獲取用戶需要異步處理的代碼,用builder
回調函數暴露出異步執行過程中的快照。我們通過builder
的參數snapshot
暴露的快照屬性,定義好對應狀態下的處理代碼,即可實現異步執行時的交互邏輯。
看起來似乎有點暈菜,可能還是不知道怎麼用,讓我們看看下面這段實戰代碼:
snapshot.connectionState
就是異步函數get(widget.newsType)
的執行狀態,用戶通過定義在ConnectionState.none
和ConnectionState.waiting
狀態下,輸出一個居中(Center
)顯示並且內置文字(Text
)爲loading...的卡片(Card
),其意義即:當異步函數get(widget.newsType)
未執行和正在執行時,屏幕正中央顯示文字:loading...。當
get(widget.newsType)
執行完畢後,snapshot.connectionState
的值即變爲ConnectionState.done
,此時即可輸出根據HTTP請求獲取到的數據生成對應的ListItem。由於ConnectionState.done
是除了ConnectionState.none
和ConnectionState.waiting
以外的唯一值,所以代碼中在switch
下用default
即可。
由於通過FutureBuilder內的builder()
函數即可操控控件的狀態和重繪,碼農不必通過自己寫異步狀態的判斷和多次使用setState()
實現頁面上加載中和加載完成顯示效果的切換,因爲FutureBuilder內部自帶了執行setState()
的方法。
懶加載就這麼輕鬆實現了,玩家還可以自己定義更漂亮的加載中的提示控件,FutureBuilder的控件化非常的純淨和徹底,它只做異步監視,沒有內置可視化控件,視覺上的處理完全交由玩家自行定義,可玩度非常高,相信很多IO操作都會用到這個控件。
RefreshIndicator的用法和實現
RefreshIndicator是Flutter基於Material設計語言內置的控件,集合了下拉手勢、加載指示器和刷新操作一體,可玩性比FutureBuilder差了一大截,不過大家也用過Material設計語言的其他控件,視覺效果也不賴的,先看看控件的基本結構:
RefreshIndicator(
//RefreshIndicator的子元素必須是一個可以滾動的控件
//如果你遇到不符合條件的控件,請將其用可以滾動的控件(如ListView、PageView等)包裝一下
child: new ScrollableWidget,
onRefresh: loadData, //onRefresh的回調必須是一個Future<Null>類型
)
這個控件的使用非常簡單,相信大家很容易理解,然後我們來看看實戰代碼:
是不是很簡單,如果你想對某個控件實現下拉手勢刷新的效果,用RefreshIndicator包裝一下,分分鐘搞定。但需要注意的就是onRefresh
的回調函數必須是Future<Null>
類型,另外其回調函數內部,必須要有setState()
句柄,哪怕你不更新任何狀態值,如果沒有這句,子控件就不會發生刷新動作,這樣明顯是消耗性能且非常不優雅的,奈何現在還不夠強大的我找不到其他辦法廢掉setState()
,暫時先滿足基本要求吧,至於什麼時候解決這個問題,應該是屬於家祭無忘告乃翁系列事件吧~
最後
全篇的代碼,大家可以到我的Git中下載,將來我還會在這個APP中添加更多的功能和代碼註釋,喜歡的同學也可以star
我一下,哈哈哈,讓我也浪一波。
本篇內容不多,對Future慾望強烈的玩家,完全可以在IDE中Ctrl
+鼠標左鍵點擊代碼中的Future或FutureBuilder關鍵字,到Flutter源碼中查看其原理和說明,當然了,和官網的內容是一模一樣的。
官方文檔更新很頻繁,看得出谷歌推Flutter真的是誠意滿滿,喜歡Flutter的小夥伴,也可以加入到Flutter圈子或flutter 中文社區(官方QQ羣:338252156),羣裏有前後端及全棧各路大神鎮場子,加入進來沒事就寫寫APP掙點外快(這個真的有),順便翻譯翻譯官方英文原稿拉一票粉絲,一舉多得何樂而不爲呢。