在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. nginx启动、关闭、重启及常用的命令

    nginx常用命令 启动:cd /usr/local/nginx/sbin./nginxnginx服务启动后默认的进程号会放在/usr/local/nginx/logs/nginx.pid文件cat ...

  2. How to: Use a Custom User Name and Password Validator(WCF)

    在wcf中使用自定义的用户名和密码验证方式 https://msdn.microsoft.com/en-us/library/aa702565.aspx http://www.codeproject. ...

  3. hive sql基础了解

    会有些不一样 1 例如使用SQL 之前,要了解用了那个库,use jz_daojia 2 使用GET_JSON_OBJECT 函数等,以及参数 匹配 $.childBrithDay 挺有意思的.新玩意 ...

  4. drf:筛选,序列化

    1.基础 restful规范: - url:一般用名词 http://www.baidu.com/article (面向资源编程) - 根据请求方式的不同做不同操作:get,post,put,dele ...

  5. upc组队赛16 GCDLCM 【Pollard_Rho大数质因数分解】

    GCDLCM 题目链接 题目描述 In FZU ACM team, BroterJ and Silchen are good friends, and they often play some int ...

  6. django 视图与网址

    我是一个新手,内容粗糙,望大家多多指点.在这里我只是总结自身所学. 视图与网址 操作文件:urls.py.views.py urls.py 作用:用于处理前台的链接(如前台访问:127.0.0.1:8 ...

  7. spring data jpa 一对多查询

    在一对多关系中,我们习惯把一的一方称之为主表,把多的一方称之为从表.在数据库中建立一对多的关系,需要使用数据库的外键约束. 什么是外键? 指的是从表中有一列,取值参照主表的主键,这一列就是外键. pa ...

  8. VC++实现窗口置顶

    最近在跟着Visual C++网络编程开发与实战视频教程做HttpSourceViewer这个MFC项目时,可以看我Github上的项目HttpSourceViewer,目前基本实现了所有功能,就是关 ...

  9. C++中的异常处理(下)

    1,catch 语句块中可以抛出异常: 1,示意图: 2,func() 在 try 语句块中,说明它有可能抛出异常,抛出的异常有可能是整型或其它类型: 3,catch 语句块处理方式是将异常重新抛出去 ...

  10. Elasticsearch学习,请先看这一篇

    题记: Elasticsearch研究有一段时间了,现特将Elasticsearch相关核心知识.原理从初学者认知.学习的角度,从以下9个方面进行详细梳理.欢迎讨论-- 0. 带着问题上路--ES是如 ...