简介
咱们晓得Flutter中有两种Widget,别离是StatelessWidget和StatefulWidget,StatelessWidget中有一个build办法来创立对应的Widget,尽管StatefulWidget中没有对应的build办法,然而和StatefulWidget对应的State中也有同样的build办法。
这个build办法就是用来创立Widget的外围办法。
咱们来看下build办法的定义:
Widget build(BuildContext context);
build办法传入一个BuildContext对象,返回一个Widget对象,也就是说这个BuildContext中蕴含了要创立的Widget的所有信息。这个BuildContext被称为是Widget的上下文构建环境。
那么BuildContext有什么个性呢?咱们又该如何应用BuildContext呢?一起来看看吧。
BuildContext的实质
还记得flutter中的三颗树吗?
他们别离是Widgets树,Element树和Render树。其中Widgets树和Element树是一一对应的。而Render树和Element中的RenderObjectElement是一一对应的。
事实上BuildContext就是一个Element对象。怎么说呢?
咱们先看下BuildContext的定义:
abstract class BuildContext {
Widget get widget;
...
}
BuildContext是一个抽象类,咱们再看一下Element类的定义:
abstract class Element extends DiagnosticableTree implements BuildContext {
能够看到,Element对象实现了BuildContext接口,而每一个BuildContext都有一个和其绑定的Widget对象。
通过简单的关系传递运算,咱们能够晓得Element对象和Widget对象从代码层面来说,的确是一一对应的。
BuildContext和InheritedWidget
InheritedWidget是一种widget用来在tree中向下传递变动信息,在tree的子节点中,能够通过调用BuildContext.dependOnInheritedWidgetOfExactType在子节点中查找最近的父InheritedWidget,从而将以后的BuildContext绑定的widget和InheritedWidget建设绑定关系,从而在下次InheritedWidget产生变动的时候,会主动触发BuildContext绑定的widget的rebuild办法。
听起来如同很简单的样子,然而实际上很简略,咱们举个例子,首先咱们须要定义一个Widget用来继承InheritedWidget:
class FrogColor extends InheritedWidget {
const FrogColor({
Key? key,
required this.color,
required Widget child,
}) : super(key: key, child: child);
final Color color;
static FrogColor of(BuildContext context) {
final FrogColor? result = context.dependOnInheritedWidgetOfExactType<FrogColor>();
assert(result != null, 'No FrogColor found in context');
return result!;
}
@override
bool updateShouldNotify(FrogColor old) => color != old.color;
}
在这个办法中,咱们须要定义一个of办法,这个该办法中,咱们调用context.dependOnInheritedWidgetOfExactType办法,用来查找离BuildContext最近的FrogColor。
而后能够这样应用:
class MyPage extends StatelessWidget {
const MyPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: FrogColor(
color: Colors.green,
child: Builder(
builder: (BuildContext innerContext) {
return Text(
'Hello Frog',
style: TextStyle(color: FrogColor.of(innerContext).color),
);
},
),
),
);
}
}
咱们的本意是心愿child中的Text组件的style依据父widget中的FrogColor的color来进行变动。所以在子组件的style中调用了FrogColor.of(innerContext)办法,对InheritedWidget进行查找,同时建设绑定关系。
在BuildContext中,有两个查找并且进行绑定的办法,他们是:
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect });
T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({ Object? aspect });
两者的区别是,后者限定了查找的类型。
除了dependOn之外,BuildContext还提供了两个查找的办法:
InheritedElement? getElementForInheritedWidgetOfExactType<T extends InheritedWidget>();
T? findAncestorWidgetOfExactType<T extends Widget>();
T? findAncestorStateOfType<T extends State>();
T? findRootAncestorStateOfType<T extends State>();
T? findAncestorRenderObjectOfType<T extends RenderObject>();
他们和depend的区别是,他们不会建设依赖关系,只是单纯的进行查找。
BuildContext的层级关系
因为每个widget都有一个BuildContext,所以咱们在应用的过程中肯定要留神传入的BuildContext到底绑定的是哪个widget。
如上面的代码所示:
class MyPage extends StatelessWidget {
const MyPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: FrogColor(
color: Colors.green,
child: Builder(
builder: (BuildContext innerContext) {
return Text(
'Hello Frog',
style: TextStyle(color: FrogColor.of(innerContext).color),
);
},
),
),
);
}
}
在FrogColor的child中,咱们创立了一个新的Builder,并提供了一个新的innerContext。
为什么要这样做呢?因为如果咱们不创立子innnerContext的话,应用的context就是Scaffold的,这样FrogColor.of将会找不到要找的对象,从而报错。
所以咱们在应用BuildContext的时候,肯定要留神。
总结
BuildContext是构建Widget的根底,它也提供了一些十分有用的查找和绑定的性能,心愿能对大家有所帮忙。
更多内容请参考 http://www.flydean.com/04-flutter-buildcontext/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」,懂技术,更懂你!
发表回复