Flutter中實現無Context跳轉

入魔的冬瓜發表於2019-09-01

背景介紹

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類:

Flutter中實現無Context跳轉

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

簡單的程式碼實現

  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物件了。

Flutter中實現無Context跳轉

  • MaterialApp類,提供了navigatorObservers屬性,這樣我們就可以自定義NavigatorObserver去監聽Navigator的變化。
    Flutter中實現無Context跳轉
  • NavigatorState類,執行instState物件的時候,會將自身賦值到監聽的所有observer物件的_navigator裡面。
    Flutter中實現無Context跳轉

簡單的程式碼實現

  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");
複製程式碼

參考文章

其實這類文章掘金上面也有,自己寫這篇文章,主要是自己做下總結。

大佬們的文章連結:

Flutter | 通過 ServiceLocator 實現無 context 導航

Flutter上線專案實戰——路由篇

相關文章