【Flutter學習】一些重要的概念之of(context)方法


在flutter中我們經常會使用到這樣的代碼

//打開一個新的頁面
  Navigator.of(context).push
//打開Scaffold的Drawer
  Scaffold.of(context).openDrawer
//獲取display1樣式文字主題
  Theme.of(context).textTheme.display1

那么這個of(context)到底是個什么呢。我們這里以Navigator打開新頁面為例。

static NavigatorState of(
  BuildContext context, {
  bool rootNavigator = false,
  bool nullOk = false,
}) {
//關鍵代碼-----------------------------------------v
final NavigatorState navigator = rootNavigator
? context.rootAncestorStateOfType(const TypeMatcher<NavigatorState>())
: context.ancestorStateOfType(const TypeMatcher<NavigatorState>()
);
//關鍵代碼----------------------------------------^ assert(() { if (navigator == null && !nullOk) { throw FlutterError( 'Navigator operation requested with a context that does not include a Navigator.\n' 'The context used to push or pop routes from the Navigator must be that of a ' 'widget that is a descendant of a Navigator widget.' ); } return true; }()); return navigator; }

可以看到,關鍵代碼部分通過context.rootAncestorStateOfType向上遍歷 Element tree,並找到最近匹配的 NavigatorState。也就是說of實際上是對context跨組件獲取數據的一個封裝。
而我們的Navigator的 push操作就是通過找到的 NavigatorState 來完成的。

不僅如此,BuildContext還有許多方法可以跨組件獲取對象

ancestorInheritedElementForWidgetOfExactType(Type targetType) → InheritedElement

ancestorRenderObjectOfType(TypeMatcher matcher) → RenderObject

ancestorStateOfType(TypeMatcher matcher) → State

ancestorWidgetOfExactType(Type targetType) → Widget

findRenderObject() → RenderObject

inheritFromElement(InheritedElement ancestor, { Object aspect }) → InheritedWidget

inheritFromWidgetOfExactType(Type targetType, { Object aspect }) → InheritedWidget

rootAncestorStateOfType(TypeMatcher matcher) → State

visitAncestorElements(bool visitor(Element element)) → void

visitChildElements(ElementVisitor visitor) → void

需要注意的是,在 State 中 initState階段是無法跨組件拿數據的,只有在didChangeDependencies之后才可以使用這些方法。

回顧問題
我們現在再來看看之前遇到的 當前 context 不包含 Navigator 這個問題是不是很簡單了呢。

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
 return MaterialApp(
  home: Scaffold(
  body: Center(
  child: FlatButton(
     onPressed: () {
       Navigator.of(context).push(
       MaterialPageRoute(builder: (context) => SecondPage()));
      },
     child: Text('跳轉')),
  ),
),
);
}
}

當我們在 build 函數中使用Navigator.of(context)的時候,這個context實際上是通過 MyApp 這個widget創建出來的Element對象,而of方法向上尋找祖先節點的時候(MyApp的祖先節點)並不存在MaterialApp,也就沒有它所提供的Navigator。
所以當我們把Scaffold部分拆成另外一個widget的時候,我們在FirstPage的build函數中,獲得了FirstPage的BuildContext,然后向上尋找發現了MaterialApp,並找到它提供的Navigator,於是就可以愉快進行頁面跳轉了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM