在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,于是就可以愉快进行页面跳转了。

【Flutter学习】一些重要的概念之of(context)方法的更多相关文章

  1. Flutter学习笔记(8)--Dart面向对象

    如需转载,请注明出处:Flutter学习笔记(7)--Dart异常处理 Dart作为高级语言,支持面向对象的很多特性,并且支持基于mixin的继承方式,基于mixin的继承方式是指:一个类可以继承自多 ...

  2. Flutter学习笔记(24)--SingleChildScrollView滚动组件

    如需转载,请注明出处:Flutter学习笔记(23)--多 在我们实际的项目开发中,经常会遇到页面UI内容过多,导致手机一屏展示不完的情况出现,以Android为例,在Android中遇到这类情况的做 ...

  3. Flutter学习笔记(25)--ListView实现上拉刷新下拉加载

    如需转载,请注明出处:Flutter学习笔记(25)--ListView实现上拉刷新下拉加载 前面我们有写过ListView的使用:Flutter学习笔记(12)--列表组件,当列表的数据非常多时,需 ...

  4. Flutter学习笔记(27)--数据共享(InheritedWidget)

    如需转载,请注明出处:Flutter学习笔记(27)--数据共享(InheritedWidget) InheritedWidget是Flutter中非常重要的一个功能型组件,它提供了一种数据在widg ...

  5. 【Flutter学习】页面布局之其它布局处理

    一,概述 Flutter中拥有30多种预定义的布局widget,常用的有Container.Padding.Center.Flex.Row.Colum.ListView.GridView.按照< ...

  6. 【Flutter学习】页面布局之基础布局组件

    一,概述 Flutter中拥有30多种预定义的布局widget,常用的有Container.Padding.Center.Flex.Row.Colum.ListView.GridView.按照< ...

  7. Flutter 学习路线图

    Flutter 学习路线图 如果你真的觉得很难,坚持不了了,那就放弃,既然放弃了就不要抱怨没有得到. 选择你热爱的,坚持你选择的,不抱怨放弃的. 前言 Flutter越来越火,学习Flutter的人越 ...

  8. Flutter学习六之实现一个带筛选的列表页面

    上期实现了一个网络轮播图的效果,自定义了一个轮播图组件,继承自StatefulWidget,我们知道Flutter中并没有像Android中activity的概念.页面见的跳转是通过路由从一个全屏组件 ...

  9. Optaplanner逐步学习(0) : 基本概念 - Optaplanner,规划问题, 约束,方案

    之前的文章中,分别从APS,排产到规划引擎叙述了一些理论基础:并介绍了一些Optaplanner大概的情况:并一步步将Optaplanner的示例运行起来,将示例源码导进Eclipse分析了一下它的H ...

随机推荐

  1. 09-排序2 Insert or Merge(25 分)

    According to Wikipedia: Insertion sort iterates, consuming one input element each repetition, and gr ...

  2. 【UNR #2】黎明前的巧克力 解题报告

    [UNR #2]黎明前的巧克力 首先可以发现,等价于求 xor 和为 \(0\) 的集合个数,每个集合的划分方案数为 \(2^{|S|}\) ,其中 \(|S|\) 为集合的大小 然后可以得到一个朴素 ...

  3. C#编写ActiveX控件

    用C#编写ActiveX控件 http://www.cnblogs.com/homer/archive/2005/01/04/86473.html http://www.cnblogs.com/hom ...

  4. pytest_用例运行级别_class级

    ''' 模块级(setup_module/teardown_module)开始于模块始末, 全局的在类中不起作用 类级(setup_class/teardown_class)只在类中前后运行一次(在 ...

  5. 从xxxx检测到有潜在危险的 Request.Form 提示黄页

    相信很多朋友都遇到过"从客户端xxxxxx"检测到有潜在危险的 Request.Form 然后给一个黄页提示.然后检测代码又找不到错误的代码提示. 原因:是因为在页面里边使用了富文 ...

  6. vector代替数组

    vector代替数组 1.声明一个int向量以替代一维的数组:vector <int> a;(等于声明了一个int数组a[],大小没有指定,可以动态的向里面添加删除). 2.用vector ...

  7. codeforces gym 100345I Segment Transformations [想法题]

    题意简述 给定一个由A C G T四个字母组成的密码锁(每拨动一次 A变C C变G G变T T变A) 密码锁有n位 规定每次操作可以选取连续的一段拨动1~3次 问最少几次操作可以将初始状态变到末状态 ...

  8. CPUID

    http://en.wikipedia.org/wiki/CPUID CPUID From Wikipedia, the free encyclopedia    The CPUID opcode i ...

  9. 【ngx-ueditor】百度编辑器按下Shift键不触发contentChange事件

    背景:基于Angular 6,引入ngx-ueditor 发现现象:如果以Shift键+任意键结尾,则ngModel会丢失包含shift键的字符 例如:输入“ABC+AB++++”,则ngModel中 ...

  10. Linux操作系统(一)_常用命令

    1.系统工作命令 date  显示/设置系统时间或日期 date:显示时间 date -s “20190319 11:35:56”:设置时间 clock  显示设置硬件时钟 clock -s:以硬件时 ...