背景介紹
Navigator.of(context).push(MaterialPageRoute(builder: (context){
return DemoPage();
}));
複製程式碼
在日常的專案開發中,我們一般push一個新頁面是用上面的方法的,利用Navigator.of(context)來進行push或者pop操作。
缺點:這種情況是必須傳context的,目的是為了利用Navigator.of(context)來獲取到NavigatorState物件,然後才能進行push或者pop操作。
那如果我要實現在專案的任何地方都可以push一個新頁面的話,而這個地方有可能獲取不到context,所以這個時候,就需要實現無context跳轉。
解決方案
無context跳轉,本質就是不必要我們每次都去傳context引數,然後利用一些操作直接去獲取到當前的NavigatorState。
方案1:利用GlobalKey
- 在Flutter中,利用GolbalKey利用獲取到對應Widget的State物件。所以,這裡,我們可以通過一個GlobalKey的key值,來獲取到NavigatorState物件。
- MaterialApp中包裝了WidgetsApp,而WidgetsApp包裝了Navigator,並且將 Navigator的key屬性作為navigatorKey暴露出來了。所以,我們可以通過設定navigatorKey,然後利用這個key去獲取到NavigatorState物件。
這裡貼一下相關的原始碼,具體的大家可以自己去看原始碼。 MaterialApp類:
WidgetsApp類:可以看出,我們定義的navigatorKey,最後是會傳給Navigator的key值,所以我們在外面就可以通過key.currentState()方法來獲取到這裡的NavigatorState物件了。
class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserver {
GlobalKey<NavigatorState> _navigator;
void _updateNavigator() {
_navigator = widget.navigatorKey ?? GlobalObjectKey<NavigatorState>(this);
}
@override
Widget build(BuildContext context) {
Widget navigator;
if (_navigator != null) {
navigator = Navigator(
key: _navigator,
initialRoute: WidgetsBinding.instance.window.defaultRouteName != Navigator.defaultRouteName
? WidgetsBinding.instance.window.defaultRouteName
: widget.initialRoute ?? WidgetsBinding.instance.window.defaultRouteName,
onGenerateRoute: _onGenerateRoute,
onUnknownRoute: _onUnknownRoute,
observers: widget.navigatorObservers,
);
}
}
複製程式碼
簡單的程式碼實現
- 定義一個GlobalKey< NavigatorState>物件
static GlobalKey<NavigatorState> navigatorKey=GlobalKey();
複製程式碼
- 建立MaterialApp的物件的時候,將navigatorKey賦值給MaterialApp。
MaterialApp(
navigatorKey: Router.navigatorKey,
)
複製程式碼
- 使用GlobalKey在任意地方獲取NavigatorState物件
navigatorKey.currentState.pushNamed("/login");
複製程式碼
方案2:利用NavigatorObserver
- NavigatorObserver,看這名字,就知道是可以用來監聽Navigator的變化。比如當push一個新頁面的時候,Navigator會監聽到NavigatorState發生變化,回撥didPush()方法。
注意:NavigatorObserver裡面定義了一個NavigatorState物件navigator,所以我們可以通過自定義NavigatorObserver,然後直接利用這個navigator物件來做頁面push或者pop操作,這樣的話,我們就不用自己去利用context去獲取navigatorState物件了。
- MaterialApp類,提供了navigatorObservers屬性,這樣我們就可以自定義NavigatorObserver去監聽Navigator的變化。
- NavigatorState類,執行instState物件的時候,會將自身賦值到監聽的所有observer物件的_navigator裡面。
簡單的程式碼實現
- 自定義NavigatorObserver。
class CustomNavigatorObserver extends NavigatorObserver{
static CustomNavigatorObserver _instance;
static CustomNavigatorObserver getInstance() {
if (_instance == null) {
_instance = CustomNavigatorObserver();
}
return _instance;
}
}
複製程式碼
- 建立MaterialApp的物件的時候,將CustomNavigatorObserver賦值給MaterialApp
MaterialApp(
navigatorObservers: [CustomNavigatorObserver()],
)
複製程式碼
- 使用CustomNavigatorObserver在任意地方進行頁面操作
CustomNavigatorObserver.getInstance().navigator.pushNamed("/login");
複製程式碼
參考文章
其實這類文章掘金上面也有,自己寫這篇文章,主要是自己做下總結。
大佬們的文章連結: