实质

  1. /// [BuildContext] objects are actually [Element] objects. The [BuildContext]
  2. /// interface is used to discourage direct manipulation of [Element] objects.

这是Fluttersdk中介绍的英文,具体说的是BuildContext是一个Element的对象,并且不要直接操作这个Element对象。
笔者在开发的时候,用的最多的就是BuildContext,但一直不理解这个是什么东西,刚开始理解的时候就理解成“上下文”。

setState

这个回调函数初学者用的最多了,目的是数据改变需要刷新页面。
底部代码实现:

  1. void setState(VoidCallback fn) {
  2. ...
  3. _element!.markNeedsBuild();
  4. }

markNeedsBuild就是刷新页面的作用,当然如果用context达到同样的效果,需要这样:

  1. (context as Element).markNeedsBuild();

但我们一般不会这样去刷新页面的。

context参数

方法

  1. (context as Element).findAncestorStateOfType()
  2. (context as Element).dependOnInheritedWidgetOfExactType()

findAncestorStateOfType:指的是当前Element往父节点找,找到某种类型为止。

  1. T? findAncestorStateOfType<T extends State<StatefulWidget>>() {
  2. assert(_debugCheckStateIsActiveForAncestorLookup());
  3. Element? ancestor = _parent;
  4. while (ancestor != null) {
  5. if (ancestor is StatefulElement && ancestor.state is T)
  6. break;
  7. ancestor = ancestor._parent;
  8. }
  9. final StatefulElement? statefulAncestor = ancestor as StatefulElement?;
  10. return statefulAncestor?.state as T?;
  11. }

具体的可以看if语句中。
dependOnInheritedWidgetOfExactType:指的是以自己为节点离我最近的Widget中某个特定类型查找。

  1. T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object? aspect}) {
  2. assert(_debugCheckStateIsActiveForAncestorLookup());
  3. final InheritedElement? ancestor = _inheritedWidgets == null ? null : _inheritedWidgets![T];
  4. if (ancestor != null) {
  5. return dependOnInheritedElement(ancestor, aspect: aspect) as T;
  6. }
  7. _hadUnsatisfiedDependencies = true;
  8. return null;
  9. }

当然具体的也可以看if语句中。

用例

  1. Theme.of(context).textTheme;
  2. var screenWidth = MediaQuery.of(context).size.width;

当然这里面直接传context参数,而Theme``MediaQuery可以理解成“单例”或是“类对象”,直接通过点语法调用“类方法”,而这些类对象的生成在void main() async由系统底层生成了。

底部实现

用例中的of方法中可以看到:

  1. static MediaQueryData of(BuildContext context) {
  2. assert(context != null);
  3. assert(debugCheckHasMediaQuery(context));
  4. return context.dependOnInheritedWidgetOfExactType<MediaQuery>()!.data;
  5. }

这里会发现上面说到的方法dependOnInheritedWidgetOfExactType,就是去查找离当前节点最近的MediaQuery节点,然后返回这个Widget节点信息。

context子节点处理

每个组件都会有自己的context,当需要查找context的上层的某个Widget节点的时候,则需要context的“降级处理”。

  1. LayoutBuilder(
  2. builder: (BuildContext context, BoxConstraints constraints) {
  3. //通过子节点context去查找父组件
  4. return Container();
  5. },
  6. )

这样通过子控件的查找,就可以找到需要找的父节点。

总结

通过这些,就可以大致的了解了什么是BuildContext,其实就是一个Widget