当前位置: 首页 > news >正文

InheritedWidget

1. 什么是 InheritedWidget?

简单来说,InheritedWidget 是一个特殊的小部件,它的主要功能是沿着 widget 树向下高效地传递数据(状态)

你可以把它想象成:

  • 一个全局的信息公告牌:任何在它子树下的组件都可以来“看”这个公告牌上的信息。

  • 一个家族族谱:子孙后代都可以根据族谱来确认自己的祖先是谁。

  • React/Vue 中的 Context:如果你有前端开发经验,它的作用和 Context API 几乎一模一样。

它的核心目的是解决“逐层传递数据” 的麻烦。想象一下,如果最顶层的组件有一个数据(比如用户登录信息、主题配色),而深埋在第十层的一个小部件需要这个数据。如果没有 InheritedWidget,你就必须通过构造函数一层一层地把这个数据传递下去,非常繁琐且难以维护。

InheritedWidget 优雅地解决了这个问题。

2. 它是如何工作的?

InheritedWidget 本身不持有复杂的逻辑。它通常包裹在你的应用或某个模块的顶层。

  1. 提供数据:你创建一个继承自 InheritedWidget 的类(例如 MyDataInheritedWidget),它内部包含了你想要共享的数据(例如 themeColor)。

  2. 查找数据:在子树下的任何一个小部件中,你都可以使用一个特定的方法(如 context.dependOnInheritedWidgetOfExactType<MyDataInheritedWidget>())来向上查找最近的 MyDataInheritedWidget 实例,并从中获取到共享的数据。

  3. 建立依赖关系:当你在一个小部件中通过 context “查找”并“依赖”了一个 InheritedWidget 后,Flutter 框架就在这个小部件和这个 InheritedWidget 之间建立了一个依赖关系

3.  didChangeDependencies 和它的关系

didChangeDependencies 是 State 对象的一个生命周期方法。

  • 调用时机:当 State 对象所依赖的 InheritedWidget 发生变化时(例如,InheritedWidget 里的数据变了,它重新构建了),Flutter 框架会自动调用所有依赖了它的组件的 didChangeDependencies 方法。

  • 为什么需要它:这是一种通知机制。它告诉子组件:“嘿,你们所依赖的那个上游数据源更新了,你们可以在这里根据新数据做一些操作或者强制刷新自己了”。

工作流程串联起来就是:

  1. 一个 InheritedWidget(例如 ThemeDataInheritedWidget)内部的主题颜色从“蓝色”变成了“红色”,这导致它重新构建。

  2. Flutter 框架检测到这个变化,然后去查看有哪些组件的 State 依赖了这个 ThemeDataInheritedWidget

  3. 框架遍历这些依赖项,并一一调用它们的 didChangeDependencies 方法。

  4. 在这些组件的 didChangeDependencies 方法里,你可以选择调用 setState(() {}) 来触发自身重建。重建时,它们再次通过 context 去获取 InheritedWidget 的数据,拿到的就是最新的“红色”了。

4. 一个简单的代码示例

// 1. 创建一个继承自 InheritedWidget 的类,用于共享主题颜色
class ThemeColorInheritedWidget extends InheritedWidget {final Color themeColor; // 要共享的数据const ThemeColorInheritedWidget({super.key,required this.themeColor,required super.child,});// 这个方法是判断何时通知依赖者更新的关键@overridebool updateShouldNotify(ThemeColorInheritedWidget oldWidget) {// 如果新的 themeColor 和旧的不一样,就通知所有依赖者return themeColor != oldWidget.themeColor;}// 一个便捷方法,方便子 widget 获取这个 InheritedWidget 实例static ThemeColorInheritedWidget? of(BuildContext context) {return context.dependOnInheritedWidgetOfExactType<ThemeColorInheritedWidget>();}
}// 2. 一个使用共享数据的子 Widget
class MyTextWidget extends StatefulWidget {const MyTextWidget({super.key});@overrideState<MyTextWidget> createState() => _MyTextWidgetState();
}class _MyTextWidgetState extends State<MyTextWidget> {Color? _currentColor;@overridevoid didChangeDependencies() {super.didChangeDependencies();// 当所依赖的 ThemeColorInheritedWidget 改变时,这个方法会被调用// 我们在这里获取最新的颜色,并更新自身状态final newColor = ThemeColorInheritedWidget.of(context)?.themeColor;if (newColor != null && newColor != _currentColor) {setState(() {_currentColor = newColor;});}}@overrideWidget build(BuildContext context) {// 初始化和构建时获取颜色_currentColor ??= ThemeColorInheritedWidget.of(context)?.themeColor;return Text('Hello World',style: TextStyle(color: _currentColor ?? Colors.black),);}
}// 3. 在应用顶层使用它
void main() {runApp(const MyApp());
}class MyApp extends StatefulWidget {const MyApp({super.key});@overrideState<MyApp> createState() => _MyAppState();
}class _MyAppState extends State<MyApp> {Color _currentThemeColor = Colors.blue;void _changeTheme() {setState(() {// 切换主题颜色,这会使得 ThemeColorInheritedWidget 重建_currentThemeColor =_currentThemeColor == Colors.blue ? Colors.red : Colors.blue;});}@overrideWidget build(BuildContext context) {return MaterialApp(home: Scaffold(appBar: AppBar(title: const Text('InheritedWidget Example'),),body: ThemeColorInheritedWidget(// 将颜色数据提供给子树themeColor: _currentThemeColor,child: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [const MyTextWidget(), // 这个 widget 会依赖上面的主题色ElevatedButton(onPressed: _changeTheme,child: const Text('Change Theme Color'),),],),),),),);}
}

在这个例子中:

  1. 点击按钮,调用 _changeTheme,改变 _currentThemeColor

  2. 这导致顶层的 ThemeColorInheritedWidget 重新构建。

  3. 它的 updateShouldNotify 方法返回 true(因为颜色确实变了)。

  4. Flutter 通知依赖了它的 _MyTextWidgetState,调用其 didChangeDependencies 方法。

  5. 在 didChangeDependencies 中,我们获取新的颜色并通过 setState 更新自己,文本颜色随之改变。

5. 怎样理解didChangeDependencies 只是一个通知机制?

Q:如果_MyTextWidgetState 里面的didChangeDependencies方法里没有调用setState,那_MyTextWidgetState 的build会执行吗?

A:不会。

如果 didChangeDependencies 方法里没有调用 setState,那么 _MyTextWidgetState 的 build 方法不会因为 InheritedWidget 的变更而被再次执行

详细解释:

让我们来分解一下整个流程,理解为什么不会:

  1. 触发变更ThemeColorInheritedWidget 的数据(themeColor)改变了,导致它重新构建。

  2. 通知依赖项:在重建时,Flutter 会调用 ThemeColorInheritedWidget 的 updateShouldNotify 方法。如果返回 true,Flutter 框架就知道需要通知所有依赖于此 InheritedWidget 的 State 对象。

  3. 调用 didChangeDependencies:框架遍历所有依赖项,并调用它们的 didChangeDependencies 方法。这一步只是一个“通知”,它本身并不会引起组件重建。

  4. 重建的关键 - setStatedidChangeDependencies 只是一个回调方法,一个让你有机会对依赖变更做出反应的钩子。你是否要做出反应(即重新构建 UI)完全取决于你。你通过调用 setState 来明确告诉 Flutter:“我收到了通知,并且我的状态需要更新,请重新构建我的 UI”。如果你不调用 setState,Flutter 就认为这个 State 虽然依赖变了,但不需要更新 UI,因此不会调用 build 方法。

类比

可以把这想象成一个新闻订阅:

  • InheritedWidget:是一家报社。

  • didChangeDependencies:是报社将新一期的报纸(数据变了)投递到你家的邮箱里。你知道有新报纸了(通知已送达)。

  • setState:是你决定走去邮箱拿出报纸并阅读它(读取新数据)的这个动作。这个动作会导致你的知识状态更新(UI 状态更新)。

  • build 方法:是根据你刚读到的新闻内容,向别人复述(重建 UI)。

如果你只是知道报纸送到了(didChangeDependencies 被调用),但懒得去拿(不调用 setState),那么你就不会获得新信息,你向别人复述的内容(build 产生的 UI)自然也就还是旧的。

划重点:

  • didChangeDependencies 只是一个通知机制

  • setState 是请求重建的机制。

  • build 是执行重建的过程。

通知 (didChangeDependencies) 并不会自动导致重建 (build),你必须手动将两者通过 setState 连接起来。 这种设计给了开发者更大的灵活性,你可以选择在某些依赖变更时忽略UI更新,或者只执行一些其他逻辑(如日志记录、网络请求等)。

总结

概念角色
InheritedWidget数据的提供者。像一个广播塔,负责持有数据和通知变更。
didChangeDependencies消费者的响应器。当广播塔(InheritedWidget)的信号变了,依赖它的消费者就会收到这个回调,从而做出反应。
依赖关系通过 context.dependOnInheritedWidgetOfExactType 建立的联系,框架借此知道该通知谁。

虽然在实际开发中,我们更多地使用 ProviderBloc 等基于 InheritedWidget 封装的先进状态管理库,但理解其底层原理 InheritedWidget 和 didChangeDependencies 的工作机制对于深入掌握 Flutter 至关重要。

http://www.dtcms.com/a/367233.html

相关文章:

  • 2025数学建模国赛高教社杯C题思路代码文章助攻
  • 超细整理,全链路性能测试-容量评估与规划,看这篇就够了...
  • Java ConcurrentModificationException 深度剖析开发调试日志
  • 从群体偏好到解构对齐:大模型强化学习从GRPO到DAPO的“认知”进化
  • https + 域名 + 客户端证书访问模式
  • Python中将方法转为属性式访问
  • Flutter之riverpod状态管理详解
  • 【计算机网络(自顶向下方法 第7版)】第一章 计算机网络概述
  • 从零开始的python学习——元组
  • 晨控CK-GW08S与汇川H5U系列PLC配置Ethernet/IP通讯连接手册
  • 别再跟风通用大模型了!企业自建专属 AI 大模型的「避坑指南 + 落地干货」
  • GitHub每日最火火火项目(9.4)
  • Linux命令和使用
  • 【数学建模学习笔记】机器学习回归:决策树回归
  • Qt---状态机框架QState
  • Java ForkJoin
  • 办公任务分发项目 laravel vue mysql 第一章:核心功能构建 API
  • Dify 低代码平台技术详解与实践
  • 实验室智能化管理信息系统如何重塑实验室运作模式?
  • Linux系统shell脚本(三)
  • 解密注意力计算的并行机制:从多头并张量操作到CUDA内核优化
  • 【Luogu_P5839】 [USACO19DEC] Moortal Cowmbat G【动态规划】
  • C语言(长期更新)第14讲:指针详解(四)
  • 第六章 Cesium 实现简易河流效果
  • FastDDS:第三节(3.2小节)
  • 规则引擎开发现在已经演化成算法引擎了
  • #T1359. 围成面积
  • Java并发编程:sleep()与wait()核心区别详解
  • 通过Interface扫描获取所有其实现类
  • AI 浪潮下阿里云“高光”乍现,但离终局胜利尚远