在路由剖析前篇已經講了Navigator的初始化,路由的映射生成以及觀察訂閱,這個篇章則會側重於路由的形態以及路由的本質。git
咱們仍是回到NavigatorState
的push
方法,github
方法雖然不長,信息量卻很多,簡要來講,有這麼幾點:ide
作的事情無外乎就是從_history
取出oldRoute
, 把route
加入_history
,而後各自調用oldRoute
,route
的一些相似生命週期的方法, 最後返回route.poped
。其中有個很特別的地方是調用了route.install()
,這個咱們待會再講。post
_history
很好理解,它是個List
,做爲棧存儲每個路由,push, pop操做分別對應List
的add
,removeLast
。學習
接着咱們看到Route
這個類,鋪墊了這麼久,終於要見到路由本尊了,老規矩,先一覽全部👀。ui
Route
的內置方法咱們能夠簡單分紅三類:
didPop
,didPush
等等isCurrent
,isFirst
,isActive
等前兩類咱們就不講了,由於知其名而知其意😎。而install
就神祕的很,畢竟它就是路由的核心了,不知道讀者們有沒有發現,其實講到如今,Navigator
和Route
的關聯仍是很模糊,而install
將會揭開這二者之間的鮮爲人知的祕密(別問我爲何知道的這麼清楚,由於我事先看過🤣)。spa
對於install
方法,其中有個很重要的類,那就是OverlayEntity
, 它提供了Overlay
所須要的信息,如opaque
等,而Overlay
如其名,是一個懸浮覆蓋的widget,因此說一個好的名字是多麼重要,相信大家也恍然大悟了吧。路由的本質就是就是把咱們的頁面包含在Overlay
這個widget裏面,而後覆蓋在舊的頁面上去。因此對於彈框來講,也就很好理解了,就是把彈框放入一個透明的Overlay
裏面,而後蓋在當前的頁面上面,牛逼🐮!
知道這個關聯以後,咱們下一步就是找出Route
到OverlayEntity
的轉換關係,咱們先從平時使用的MaterialPageRoute
入手,深扒它的父類,最後在ModalRoute
找到了這麼一個方法,3d
@override
Iterable<OverlayEntry> createOverlayEntries() sync* {
yield _modalBarrier = OverlayEntry(builder: _buildModalBarrier);
yield OverlayEntry(builder: _buildModalScope, maintainState: maintainState);
}
複製代碼
接着咱們順藤摸瓜,找到ModalRoute
對應的build
方法,看到了這麼一個關鍵:code
widget.route.buildPage
這不是擺明告訴咱們是在這裏建立的頁面嗎,而後咱們返回MaterialPageRoute
,果不其然cdn
因此,綜上,咱們的路由頁面經過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,查看完整代碼。