Flutter中實現無Context跳轉

背景介紹

Navigator.of(context).push(MaterialPageRoute(builder: (context){
          return DemoPage();
        }));
複製代碼

在平常的項目開發中,咱們通常push一個新頁面是用上面的方法的,利用Navigator.of(context)來進行push或者pop操做。bash

缺點:這種狀況是必須傳context的,目的是爲了利用Navigator.of(context)來獲取到NavigatorState對象,而後才能進行push或者pop操做。ide

那若是我要實如今項目的任何地方均可以push一個新頁面的話,而這個地方有可能獲取不到context,因此這個時候,就須要實現無context跳轉。post

解決方案

無context跳轉,本質就是沒必要要咱們每次都去傳context參數,而後利用一些操做直接去獲取到當前的NavigatorState。ui

方案1:利用GlobalKey

  • 在Flutter中,利用GolbalKey利用獲取到對應Widget的State對象。因此,這裏,咱們能夠經過一個GlobalKey的key值,來獲取到NavigatorState對象。
  • MaterialApp中包裝了WidgetsApp,而WidgetsApp包裝了Navigator,而且將 Navigator的key屬性做爲navigatorKey暴露出來了。因此,咱們能夠經過設置navigatorKey,而後利用這個key去獲取到NavigatorState對象。

這裏貼一下相關的源碼,具體的你們能夠本身去看源碼。 MaterialApp類: this

WidgetsApp類:能夠看出,咱們定義的navigatorKey,最後是會傳給Navigator的key值,因此咱們在外面就能夠經過key.currentState()方法來獲取到這裏的NavigatorState對象了。spa

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,
      );
    }
}
複製代碼

簡單的代碼實現

  1. 定義一個GlobalKey< NavigatorState>對象
static GlobalKey<NavigatorState> navigatorKey=GlobalKey();
複製代碼
  1. 建立MaterialApp的對象的時候,將navigatorKey賦值給MaterialApp。
MaterialApp(
          navigatorKey: Router.navigatorKey,
)
複製代碼
  1. 使用GlobalKey在任意地方獲取NavigatorState對象
navigatorKey.currentState.pushNamed("/login");
複製代碼

方案2:利用NavigatorObserver

  • NavigatorObserver,看這名字,就知道是能夠用來監聽Navigator的變化。好比當push一個新頁面的時候,Navigator會監聽到NavigatorState發生變化,回調didPush()方法。

注意:NavigatorObserver裏面定義了一個NavigatorState對象navigator,因此咱們能夠經過自定義NavigatorObserver,而後直接利用這個navigator對象來作頁面push或者pop操做,這樣的話,咱們就不用本身去利用context去獲取navigatorState對象了。 3d

  • MaterialApp類,提供了navigatorObservers屬性,這樣咱們就能夠自定義NavigatorObserver去監聽Navigator的變化。
  • NavigatorState類,執行instState對象的時候,會將自身賦值到監聽的全部observer對象的_navigator裏面。

簡單的代碼實現

  1. 自定義NavigatorObserver。
class CustomNavigatorObserver extends NavigatorObserver{
  static CustomNavigatorObserver _instance;

  static CustomNavigatorObserver getInstance() {
    if (_instance == null) {
      _instance = CustomNavigatorObserver();
    }
    return _instance;
  }
}
複製代碼
  1. 建立MaterialApp的對象的時候,將CustomNavigatorObserver賦值給MaterialApp
MaterialApp(
          navigatorObservers: [CustomNavigatorObserver()],
)
複製代碼
  1. 使用CustomNavigatorObserver在任意地方進行頁面操做
CustomNavigatorObserver.getInstance().navigator.pushNamed("/login");
複製代碼

參考文章

其實這類文章掘金上面也有,本身寫這篇文章,主要是本身作下總結。code

大佬們的文章連接:cdn

Flutter | 經過 ServiceLocator 實現無 context 導航 server

Flutter上線項目實戰——路由篇

相關文章
相關標籤/搜索