内容提要
本文介绍 Flutter 中 InheritedWidget 的使用与原理:它作为根节点实现跨同级 Widget 数据共享,子控件通过 of 方法注册依赖,数据变化时触发 didChangeDependencies 刷新;文章还分析 Widget、Element、Render 三棵树及依赖注册机制,并说明 updateShouldNotify 如何通知子节点重建。
延伸解读
依赖注册:of 与 getElement 的关键区别
子控件通过 of 方法调用 dependOnInheritedWidgetOfExactType 会注册依赖,数据变化时触发 didChangeDependencies;而 getElementForInheritedWidgetOfExactType 仅获取 InheritedWidget 实例,不注册依赖,因此不会响应回调。例如右边栏只修改数据而不显示,使用后者可避免不必要的重建,提升性能。
三棵树协作:Element 作为更新桥梁
Widget 树描述配置,Element 树与之对应,Render 树仅与 RenderObjectElement 对应。setState 重建 Widget 成本低,Element 比较新旧 Widget,若仅数据变化则更新 Render 树数据而不重建,从而高效刷新 UI。理解此机制有助于把握 InheritedWidget 的更新时机。
InheritedElement 的查找与覆盖规则
InheritedElement 在 mount 时会将自身添加到 _inheritedElements,替换父节点中同类型的 InheritedElement。因此子节点通过 of 查找时,只能找到离它最近的那个 InheritedWidget。例如嵌套两个 SharedDataWidget,内层会覆盖外层,Text 获取的是内层数据。
updateShouldNotify 与通知流程
当 InheritedWidget 数据变化时,InheritedElement 的 updated 方法根据 updateShouldNotify 判断是否通知。若返回 true,则遍历 _dependents 调用每个依赖节点的 didChangeDependencies,进而 markNeedsBuild 触发重建。因此正确实现 updateShouldNotify 是避免无效刷新的关键。
Q&A
Flutter 中 InheritedWidget 是什么?它有什么作用?
InheritedWidget 是 Flutter 中用于跨组件共享数据的控件,通常作为根节点,让子控件通过 of 方法获取共享数据并注册依赖,当数据变化时自动通知子控件刷新。
如何使用 InheritedWidget 实现同级 Widget 之间的数据共享?
创建一个继承自 InheritedWidget 的类,定义共享数据和修改方法,并实现 updateShouldNotify 和 of 静态方法。将 InheritedWidget 作为根节点包裹需要共享数据的子控件,子控件通过 of 方法获取数据,修改数据时调用 setState 触发重建。
InheritedWidget 的 updateShouldNotify 方法有什么作用?
updateShouldNotify 用于判断 InheritedWidget 的数据是否发生变化,如果返回 true,则会通知依赖的子控件调用 didChangeDependencies 方法,进而触发重建。
dependOnInheritedWidgetOfExactType 和 getElementForInheritedWidgetOfExactType 有什么区别?
dependOnInheritedWidgetOfExactType 会注册依赖关系,当 InheritedWidget 数据变化时子控件会收到 didChangeDependencies 回调;而 getElementForInheritedWidgetOfExactType 只获取 InheritedWidget 实例,不注册依赖,因此不会触发回调。
Flutter 中的三棵树是什么?它们之间的关系如何?
Flutter 中有 Widget 树、Element 树和 Render 树。Widget 树描述 UI 配置,Element 树与 Widget 树一一对应,Render 树只包含需要渲染的节点,与 Element 树中的 RenderObjectElement 一一对应。Element 树作为桥梁,在重建时比较 Widget 变化并更新 Render 树。
InheritedWidget 的数据变化后,子控件是如何被通知并刷新的?
当 InheritedWidget 数据变化时,InheritedElement 的 updated 方法会根据 updateShouldNotify 判断是否通知,若需要则调用依赖子控件的 didChangeDependencies 方法,进而调用 markNeedsBuild 标记重建,实现刷新。