路由, 是前端頁面永遠繞不過去的一個坎。那麼對於萬物皆widget的Flutter,路由又會以怎麼樣的形式存在呢?🔎前端
咱們先從調用入口開始跟蹤,git
Navigator.of(context).pushNamed("xxx")
github
那咱們就直接進入Navigator這個文件,文件的結構以下:數組
涉及到幾個類,分別 RoutePopDisposition,Route,RouteSettings.NavigatorObserver,Navigator,NavigatorState
這幾個類就是咱們瞭解路由的基礎了,咱們先看到Navigator
, 好傢伙,Navigator
果真又是一個Widget😏,接着利用Android Studio找出調用它的地方,以下:markdown
咱們先到app.dart一探究竟, 發現這裏是對Navigator作了初始化工做 ,app
不過,仔細瞧瞧,發現這裏又有一個上面提到的類—— NavigatorObserver
, 那先過去看看咯。less
/// An interface for observing the behavior of a [Navigator].
class NavigatorObserver {
/// The navigator that the observer is observing, if any.
NavigatorState get navigator => _navigator;
NavigatorState _navigator;
/// The [Navigator] pushed `route`.
///
/// The route immediately below that one, and thus the previously active
/// route, is `previousRoute`.
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) { }
/// The [Navigator] popped `route`.
///
/// The route immediately below that one, and thus the newly active
/// route, is `previousRoute`.
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) { }
/// The [Navigator] removed `route`.
///
/// If only one route is being removed, then the route immediately below
/// that one, if any, is `previousRoute`.
///
/// If multiple routes are being removed, then the route below the
/// bottommost route being removed, if any, is `previousRoute`, and this
/// method will be called once for each removed route, from the topmost route
/// to the bottommost route.
void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) { }
/// The [Navigator] replaced `oldRoute` with `newRoute`.
void didReplace({ Route<dynamic> newRoute, Route<dynamic> oldRoute }) { }
/// The [Navigator]'s route `route` is being moved by a user gesture.
///
/// For example, this is called when an iOS back gesture starts.
///
/// Paired with a call to [didStopUserGesture] when the route is no longer
/// being manipulated via user gesture.
///
/// If present, the route immediately below `route` is `previousRoute`.
/// Though the gesture may not necessarily conclude at `previousRoute` if
/// the gesture is canceled. In that case, [didStopUserGesture] is still
/// called but a follow-up [didPop] is not.
void didStartUserGesture(Route<dynamic> route, Route<dynamic> previousRoute) { }
/// User gesture is no longer controlling the [Navigator].
///
/// Paired with an earlier call to [didStartUserGesture].
void didStopUserGesture() { }
}
複製代碼
NavigatorObserver
是一個Navigator行爲的觀察者,能夠監聽到push
,remove
,pop
等行爲,它能夠在MaterialApp對屬性navigatorObservers進行設置,以下:ide
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(title: 'Flutter Demo Home Page'),
navigatorObservers: [
MyObserver()
],
routes: {
"second": (context) => SecondPage(),
},
);
}
}
複製代碼
接着咱們藉助Android Studio查看Observer的調用, 如下是其中一個調用:post
咱們能夠注意到,Navigator在push的時候調用了Observer的didPush, 第一個參數是即將push的route,第二個參數則是當前的路由頁面,這樣一來,咱們就能夠經過全局的Observer監聽到整個App的路由變化。
看到這裏,我本身內心有兩個疑惑🤔,第一個就是爲何全局的Observer要設計爲數組的形式,第二個就是咱們要怎麼在當前頁面監聽本身的路由狀態變化。學習
要解決這兩個疑惑,須要從NavigatorObserver
入手,再次藉助Android Studio(AS真是個好東西😅),不怎麼費勁就找到一個繼承自NavigatorObserver
的類RouteObserver
, 下面是它的描述:
A [Navigator] observer that notifies [RouteAware]s of changes to the state of their [Route].
此外還有一些相關的方法:
看到subscribe
, unsubscribe
了,實錘無疑了🤓,看來這個就是咱們在找的東西了,能夠監聽當前route的狀態改變。 解決了第二個疑惑,其實也就順帶解決了第一個疑惑,既然有這種觀察路由的須要,那麼意味着須要多個觀察者,那Observer設計爲數組的形式也就很合理了。
下面是簡單的用法:
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MainPage(),
navigatorObservers: [
routeObserver,
MyObserver()
],
routes: {
"設置": (context) => SettingsPage(),
},
);
}
}
複製代碼
class _SettingsPageState extends State<SettingsPage> with RouteAware{
final settingsStore = SettingsStore();
@override
void didChangeDependencies() {
super.didChangeDependencies();
settingsStore.getPrefsData();
routeObserver.subscribe(this, ModalRoute.of(context));
}
@override
void dispose() {
routeObserver.unsubscribe(this);
super.dispose();
}
@override
void didPop() {
super.didPop();
}
@override
void didPush() {
super.didPush();
}
}
複製代碼
用法也很簡單,就是增長了一個全局的觀察者,而後在使用的地方進行訂閱和註銷,這裏又發現了一個新的類RouteAware
, 天啊😢,好多類,不過嘛,其實就是個簡單的接口定義😎:
接着回過頭去看到一開始的Navigator.of(context).pushNamed("xxx")
, 發現其實是調用了NavigatorState
的pushNamed
方法,而對於pushNamed
方法,又牽涉到name映射到route的關係,咱們來看看這一段的實現:
其實邏輯很簡單,就是調用onGenerateRoute
生成route, 而且提供了兜底操做,容許使用onUnknownRoute
繼續生成route。而上面這兩個方法其實也是在MaterialApp
這個widget進行設置的,咱們照例進行了設置:
Route _onGenerateRoute(RouteSettings routeSettings) {
return null;
}
Route _onUnknownRoute(RouteSettings routeSettings) {
return MaterialPageRoute(settings:routeSettings, builder: (context) => UnKnowRoutePage());
}
複製代碼
除了這兩個屬性以外,還提供了一個可供配置的routes
,提供name到route映射的map,以下:
{
routes: <String, WidgetBuilder>{"設置": (context) => SettingsPage()},
}
複製代碼
緊接着,咱們找到看到WidgetsApp
這個widget,找到裏面的_onGenerateRoute
方法,
到這裏就豁然開朗了,優先取出routes
的路由,若是取不到,就調用onGenerateRoute
生成路由。
前篇差很少就到這裏吧,中篇纔是大頭,各類Route
滿天飛😪。
這個剖析前篇其實就是講了Navigator
的初始化,還有NavigatorObserver
的應用,經過它能夠監聽本身路由的狀態變化,而且研究了路由的生成配置原理以及兜底方案,固然講的更多的還有Android Stduio的使用,經過AS在定位代碼,查找代碼引用確實有奇效。
Flutter筆記--Flutter頁面嵌入Android Activity中
Flutter生命週期和Navigator、Route監聽
點擊flutter_demo,查看完整代碼。