導航
- Flutter學習篇(一)—— Dialog的簡單使用
- Flutter學習篇(二)—— Drawer和水紋按壓效果
- Flutter學習篇(三)—— MobX的使用和原理
- Flutter學習篇(四)—— 尺寸解惑
- Flutter學習篇(五)——路由剖析前篇
前言
在路由剖析前篇已經講了Navigator的初始化,路由的對映生成以及觀察訂閱,這個篇章則會側重於路由的形態以及路由的本質。
剖析
我們還是回到NavigatorState
的push
方法,
方法雖然不長,資訊量卻不少,簡要來說,有這麼幾點:
- Route
- _history
- return route.popped
做的事情無外乎就是從_history
取出oldRoute
, 把route
加入_history
,然後各自呼叫oldRoute
,route
的一些類似生命週期的方法, 最後返回route.poped
。其中有個很特別的地方是呼叫了route.install()
,這個我們待會再講。
_history
_history
很好理解,它是個List
,作為棧儲存每一個路由,push, pop操作分別對應List
的add
,removeLast
。
Route
接著我們看到Route
這個類,鋪墊了這麼久,終於要見到路由本尊了,老規矩,先一覽所有?。
Route
的內建方法我們可以簡單分成三類:
- 生命週期型別,
didPop
,didPush
等等 - 狀態型別,
isCurrent
,isFirst
,isActive
等 - install
前兩類我們就不講了,因為知其名而知其意?。而install
就神祕的很,畢竟它就是路由的核心了,不知道讀者們有沒有發現,其實講到現在,Navigator
和Route
的關聯還是很模糊,而install
將會揭開這兩者之間的不為人知的祕密(別問我為什麼知道的這麼清楚,因為我事先看過?)。
對於install
方法,其中有個很重要的類,那就是OverlayEntity
, 它提供了Overlay
所需要的資訊,如opaque
等,而Overlay
如其名,是一個懸浮覆蓋的widget,所以說一個好的名字是多麼重要,相信你們也恍然大悟了吧。路由的本質就是就是把我們的頁面包含在Overlay
這個widget裡面,然後覆蓋在舊的頁面上去。所以對於彈框來說,也就很好理解了,就是把彈框放入一個透明的Overlay
裡面,然後蓋在當前的頁面上面,牛逼?!
知道這個關聯之後,我們下一步就是找出Route
到OverlayEntity
的轉換關係,我們先從平時使用的MaterialPageRoute
入手,深扒它的父類,最後在ModalRoute
找到了這麼一個方法,
@override
Iterable<OverlayEntry> createOverlayEntries() sync* {
yield _modalBarrier = OverlayEntry(builder: _buildModalBarrier);
yield OverlayEntry(builder: _buildModalScope, maintainState: maintainState);
}
複製程式碼
接著我們順藤摸瓜,找到ModalRoute
對應的build
方法,看到了這麼一個關鍵:
widget.route.buildPage
這不是擺明告訴我們是在這裡建立的頁面嗎,然後我們返回MaterialPageRoute
,果不其然
所以,綜上,我們的路由頁面通過buildPage
作為widget傳遞到ModalRoute
,接著在ModalRoute
通過createOverlayEntries
將路由頁面包裝在Overlay
這個覆蓋型的widget。所以install
就是這麼一個過程,它將路由頁面對映為Overlay
,而Navigator
則負責管理路由的進出。
通訊
講完 install
,再回過頭看看剛剛的疑問,還有一個地方沒解決的,那就是push之後的返回值route.popped
, 究竟為什麼需要這麼一個返回值呢?其實這就是涉及到路由之間的通訊了,當頁面退出時,可以攜帶一些資訊回到上一個頁面。如下:
可以看到,pop
方法的引數result
傳遞到了didPop
,那我們繼續扒一扒didPop
,
這裡又發現了一個新大陸_popCompleter
?, 它是個啥呢,官方介紹如下Completer
:
A way to produce Future objects and to complete them later with a value or error.
複製程式碼
它是個可以延後執行的Future物件,那這樣一來就串起來了,路由pop
之後,執行了_popCompleter
的完成方法,引數自然就通過Future物件傳遞出去,上一個頁面只需要監聽_popCompleter
的回撥即可,這時候就輪到push
之後的返回值route.popped
登場了,沒錯,這個返回值就是_popCompleter
的Future物件,如下:
Future<T> get popped => _popCompleter.future;
複製程式碼
所以,梳理一下,當我們push
一個路由的時候,我們會拿到下一個路由的
Future物件,當下一個路由pop
的時候,Future物件就執行回撥,如下:
Navigator.of(context).push(MaterialPageRoute(builder:(context) => SettingsPage()).then((value){
print(value);
});
複製程式碼
這樣一來,我們就可以監聽到路由傳遞回來的值了。
路由分類
其實可以簡單粗暴地根據opaque
將路由劃分為兩類:
- 透明
- 不透明
對應的其實就是彈框和頁面,對於頁面級的路由,繼承自PageRoute
, 對應的opaque
為true,不透明頁面;而彈框繼承自PopupRoute
, opaque
為false,透明頁面,所以呈現為彈框的形態。
總結
其實這個篇章主要是通過深究push
方法,從中窺探路由的本質,對於路由來講,追溯到底,它還是widget
,只不過藏得比較深。其實再複雜的東西,一層一層剖開,它仍然是一個系統最基本最核心的個體,這個剖析的過程尚且容易,最難的往往是從0到1,簡單到複雜,這需要極大的智慧去搭建,組裝和落地。
倉庫
點選flutter_demo,檢視完整程式碼。