简介
咱们晓得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/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」,懂技术,更懂你!