Flutter 的 InheritedWidget

1,065 阅读2分钟

「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战」。

在前几篇基本简单的梳理了main.dart里面有些比较重要的一些知道点。。我们知道了runApp()里面的一些简单的流程以及运行机制。我们也知道了StatelessWidgetStatefulWidget的一些简单知识点,以及知道在widget树中BuildContext用来横穿上下文。我们在里面有提到了一个重要的知识点InheritedWidget。今天我们就来了解一下InheritedWidget吧。

image.png

什么是 InheritedWidget

InheritedWidget 只是一个简单的widget。他是是不可变的,除了保存data什么都不做。如果我们刷新它,就需要重建它。InheritedWidget将数据从祖先widget传递给可能位于widget树深处的后代widget。

const InheritedWidget({Key? key, required Widget child }) : super(key: key, child: child);

Flutter 自身的InheritedWidget的widget:

Theme.of(context).textTheme
MediaQuery.of(context).size

有一个名为 of() 的特殊方法,它可以访问其 Widget 树中任何位置的属性。

当实例化一个InheritedWidget,然后调用context.inheritedWidgetOfExactType(或of)时;这意味着它会侦听Element与您的InheritedWidget。 每当Element获得一个新的widget时,它将强制刷新 调用前一个方法的widget。当您用InheritedWidget全新的替换现有的时,系统会并将通知绑定的widget进行修改。

实际使用

首先,创建您自己的类来扩展 InheritedWidget 以在项目中传递数据。

class ColorInfo extends InheritedWidget {

  ColorInfo({Key? key, required this.child}) : super(key: key, child: child);

  final Widget child;

   static ColorInfo? of(BuildContext context) {
  return context.dependOnInheritedWidgetOfExactType<Name>();
}

  @override
  bool updateShouldNotify(ColorInfo oldWidget) {
    return true;
  }
}

of方法是InheritedWidget从子widget更轻松地访问您的数据的一个约定。 updateShouldNotify方法是告诉我们是否应该在数据更改时重新绘制依赖于数据的widget,oldwidget 参数允许您将 InheritedWidget 中的先前数据与新数据进行比较。

inheritFromWidgetOfExactType

@override
  InheritedWidget inheritFromWidgetOfExactType(Type targetType, { Object aspect }) {
   ///在共享 map _inheritedWidgets 中查找
    final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[targetType];
    if (ancestor != null) {
     ///返回找到的 InheritedWidget ,同时添加当前 element 处理
      return inheritFromElement(ancestor, aspect: aspect);
    }
    _hadUnsatisfiedDependencies = true;
    return null;
  }

@override
  InheritedWidget inheritFromElement(InheritedElement ancestor, { Object aspect }) {
    _dependencies ??= HashSet<InheritedElement>();
    _dependencies.add(ancestor);
  ///就是将当前 element(this) 添加到  _dependents 里
  ///也就是 InheritedElement 的 _dependents
  ///_dependents[dependent] = value;
    ancestor.updateDependencies(this, aspect);
    return ancestor.widget;
  }

@override
  void notifyClients(InheritedWidget oldWidget) {
    for (Element dependent in _dependents.keys) {
      notifyDependent(oldWidget, dependent);
    }
  }
  • 在共享 map _inheritedWidgets 中查找,如果找到,添加inheritFromElement 处理,然后返回找到的 InheritedWidget
  • 将当前的Element加入到InheritedElement_dependents这个map里面。并且交由updateDependencies去处理,在Widget中返回InheritedElement

创建一个新的 InheritedWidget 会重建整个树吗?

不一定。因为您的新 InheritedWidget 可能具有与以前完全相同的子widget(同一个实例)。拥有与之前相同实例的widget不会重建。