Flutter InheritedWidget 详解

📌 什么是 InheritedWidget

  • InheritedWidget 是 Flutter 数据向下传递 的机制。
  • 它允许你把 数据存储在 Widget 树的某个节点,树下的子组件可以直接获取这些数据,而不需要层层参数传递。
  • Flutter 的 Provider、Bloc、Theme.of、MediaQuery.of 都是基于 InheritedWidget 实现的。

📖 继承关系

plaintext 复制代码
Object
  ↳ Diagnosticable
    ↳ DiagnosticableTree
      ↳ Widget
        ↳ ProxyWidget
          ↳ InheritedWidget

🛠 使用方式

1. 定义一个 InheritedWidget

dart 复制代码
class CounterInheritedWidget extends InheritedWidget {
  final int counter;

  const CounterInheritedWidget({
    Key? key,
    required this.counter,
    required Widget child,
  }) : super(key: key, child: child);

  // 提供一个静态方法,方便子树获取数据
  static CounterInheritedWidget? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<CounterInheritedWidget>();
  }

  // 当 counter 改变时,是否通知子 Widget 重新 build
  @override
  bool updateShouldNotify(CounterInheritedWidget oldWidget) {
    return oldWidget.counter != counter;
  }
}

2. 在 Widget 树中使用

dart 复制代码
class CounterApp extends StatefulWidget {
  @override
  _CounterAppState createState() => _CounterAppState();
}

class _CounterAppState extends State<CounterApp> {
  int _counter = 0;

  void _increment() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return CounterInheritedWidget(
      counter: _counter,
      child: Scaffold(
        appBar: AppBar(title: Text("InheritedWidget Demo")),
        body: Center(child: CounterText()),
        floatingActionButton: FloatingActionButton(
          onPressed: _increment,
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}

class CounterText extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final inherited = CounterInheritedWidget.of(context);
    return Text(
      "当前计数: ${inherited?.counter}",
      style: TextStyle(fontSize: 24),
    );
  }
}

🔍 核心点

  1. 数据存放在 InheritedWidget

    • 比如 counter
  2. 子 Widget 获取数据时要用 dependOnInheritedWidgetOfExactType

    • 这样,当 InheritedWidget 更新时,子 Widget 会自动 build
  3. updateShouldNotify 控制是否通知

    • 如果返回 true,依赖它的子 Widget 会重建。
    • 如果返回 false,不会触发更新(提高性能)。

📌 实际应用

  • Flutter 内置

    • Theme.of(context) → 通过 InheritedWidget 获取主题
    • MediaQuery.of(context) → 获取屏幕信息
    • Localizations.of(context) → 获取国际化
  • 第三方库

    • ProviderRiverpodBloc 等,都是对 InheritedWidget 的封装

✅ 总结

  • InheritedWidget数据共享的基石,可以避免参数层层传递。
  • 适合做 全局状态(主题、语言、屏幕信息)局部状态共享(比如父传子、兄弟组件共享数据)
  • 在实际项目中,我们很少直接用它,而是通过 Provider / Riverpod / Bloc 等更高级的封装。