在 Flutter 中,InheritedWidget
是实现 Widget 树中跨层级数据共享的核心机制,它解决了传统通过构造函数传递数据("prop drilling")的繁琐问题,尤其适合深层级 Widget 间的数据传递。其扩展类(InheritedNotifier
、InheritedModel
等)则在基础功能上增加了更精细的状态管理能力。
一、核心概念与关系
InheritedWidget
:基类,用于在 Widget 树中高效共享数据。当数据变化时,依赖它的子 Widget 会被选择性重建。Listenable
:抽象类(类似观察者模式中的 "被观察者"),定义了添加 / 移除监听器的接口,ChangeNotifier
是其常用实现。InheritedNotifier<T extends Listenable>
:InheritedWidget
的子类,内部持有一个Listenable
对象。当Listenable
触发通知时,会自动调用updateShouldNotify
触发依赖 Widget 重建,简化了状态更新逻辑。InheritedModel<T>
:InheritedWidget
的子类,支持按 "维度(aspect)" 精确控制更新。普通InheritedWidget
数据变化时所有依赖者都会重建,而InheritedModel
可指定只有关注特定 "aspect" 的 Widget 才重建,优化性能。
二、使用场景
1. ✅InheritedWidget
:基础跨层级数据共享
适用场景:共享静态或低频变化的数据(如主题配置、用户基本信息)。
Demo:共享应用主题配置
dart
import 'package:flutter/material.dart';
// 1. 定义需要共享的数据模型
class AppTheme {
final Color primaryColor;
final TextStyle textStyle;
AppTheme({required this.primaryColor, required this.textStyle});
}
// 2. 实现 InheritedWidget 子类
class ThemeInheritedWidget extends InheritedWidget {
final AppTheme theme;
// 提供一个便捷方法供子Widget获取实例
static ThemeInheritedWidget? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<ThemeInheritedWidget>();
}
const ThemeInheritedWidget({
super.key,
required this.theme,
required super.child,
});
// 决定数据变化时是否通知依赖的Widget
@override
bool updateShouldNotify(covariant ThemeInheritedWidget oldWidget) {
// 当主题的primaryColor或textStyle变化时,通知更新
return theme.primaryColor != oldWidget.theme.primaryColor ||
theme.textStyle != oldWidget.theme.textStyle;
}
}
// 3. 子Widget使用共享数据
class ThemedText extends StatelessWidget {
final String text;
const ThemedText(this.text, {super.key});
@override
Widget build(BuildContext context) {
// 获取共享的主题数据
final theme = ThemeInheritedWidget.of(context)?.theme;
return Text(
text,
style: theme?.textStyle ?? const TextStyle(),
);
}
}
// 4. 用法示例
class InheritedWidgetDemo extends StatefulWidget {
const InheritedWidgetDemo({super.key});
@override
State<InheritedWidgetDemo> createState() => _InheritedWidgetDemoState();
}
class _InheritedWidgetDemoState extends State<InheritedWidgetDemo> {
late AppTheme currentTheme;
@override
void initState() {
super.initState();
currentTheme = AppTheme(
primaryColor: Colors.blue,
textStyle: const TextStyle(color: Colors.black, fontSize: 16),
);
}
// 切换主题
void _toggleTheme() {
setState(() {
currentTheme = AppTheme(
primaryColor: currentTheme.primaryColor == Colors.blue ? Colors.red : Colors.blue,
textStyle: currentTheme.textStyle.color == Colors.black
? const TextStyle(color: Colors.white, fontSize: 18)
: const TextStyle(color: Colors.black, fontSize: 16),
);
});
ThemeInheritedWidget.of(contetxt).apptheme = cu
}
@override
Widget build(BuildContext context) {
return ThemeInheritedWidget(
theme: currentTheme,
child: Scaffold(
appBar: AppBar(
title: const Text('InheritedWidget Demo'),
backgroundColor: currentTheme.primaryColor,
),
body: Center(
child: ThemedText('共享的主题文本'),
),
floatingActionButton: FloatingActionButton(
onPressed: _toggleTheme,
child: const Icon(Icons.color_lens),
),
),
);
}
}
关键点:
- 通过
context.dependOnInheritedWidgetOfExactType
建立依赖关系。 updateShouldNotify
决定数据变化时是否触发子 Widget 重建。
2. ✅InheritedNotifier
:结合监听者模式的状态管理
适用场景:共享高频变化且需要自动通知更新的数据(如计数器、表单状态)。
Demo:计数器状态管理
dart
import 'package:flutter/material.dart';
// 1. 定义可监听的状态(继承ChangeNotifier,实现Listenable)
class CounterNotifier extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners(); // 通知监听者(触发更新)
}
}
// 2. 实现InheritedNotifier子类
class CounterInheritedNotifier extends InheritedNotifier<CounterNotifier> {
// 提供便捷获取方法
static CounterInheritedNotifier? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<CounterInheritedNotifier>();
}
const CounterInheritedNotifier({
super.key,
required CounterNotifier notifier,
required super.child,
}) : super(notifier: notifier);
// 无需手动实现updateShouldNotify,InheritedNotifier会自动根据notifier的变化处理
}
// 3. 子Widget使用计数器
class CounterDisplay extends StatelessWidget {
const CounterDisplay({super.key});
@override
Widget build(BuildContext context) {
final notifier = CounterInheritedNotifier.of(context)?.notifier;
return Text(
'当前计数: ${notifier?.count ?? 0}',
style: const TextStyle(fontSize: 20),
);
}
}
// 4. 用法示例
class InheritedNotifierDemo extends StatelessWidget {
const InheritedNotifierDemo({super.key});
@override
Widget build(BuildContext context) {
final counterNotifier = CounterNotifier();
return CounterInheritedNotifier(
notifier: counterNotifier,
child: Scaffold(
appBar: AppBar(title: const Text('InheritedNotifier Demo')),
body: const Center(child: CounterDisplay()),
floatingActionButton: FloatingActionButton(
onPressed: counterNotifier.increment,
child: const Icon(Icons.add),
),
),
);
}
}
关键点:
- 无需手动管理
updateShouldNotify
,InheritedNotifier
会在Listenable
调用notifyListeners
时自动触发更新。 - 适合封装
ChangeNotifier
状态,简化状态管理逻辑。
3. ✅InheritedModel
:按维度精确控制更新
适用场景:共享包含多个独立维度的数据(如一个页面同时展示用户信息、商品列表、购物车数量),且需要精确控制某一维度变化时只有相关 Widget 重建。
Demo:多维度用户信息更新
dart
import 'package:flutter/material.dart';
// 1. 定义共享的数据模型(包含name和age两个维度)
class UserInfo {
final String name;
final int age;
UserInfo({required this.name, required this.age});
UserInfo copyWith({String? name, int? age}) {
return UserInfo(
name: name ?? this.name,
age: age ?? this.age,
);
}
}
// 2. 定义维度标识(aspect)
enum UserAspect { name, age }
// 3. 实现InheritedModel子类
class UserInheritedModel extends InheritedModel<UserAspect> {
final UserInfo userInfo;
static UserInheritedModel? of(BuildContext context, {UserAspect? aspect}) {
return context.dependOnInheritedWidgetOfExactType<UserInheritedModel>(
aspect: aspect, // 指定关注的维度
);
}
const UserInheritedModel({
super.key,
required this.userInfo,
required super.child,
});
// 决定某一维度变化时是否通知依赖该维度的Widget
@override
bool updateShouldNotifyDependent(
covariant UserInheritedModel oldWidget,
Set<UserAspect> dependencies,
) {
// 如果依赖name维度,且name变化,则通知
if (dependencies.contains(UserAspect.name) &&
userInfo.name != oldWidget.userInfo.name) {
return true;
}
// 如果依赖age维度,且age变化,则通知
if (dependencies.contains(UserAspect.age) &&
userInfo.age != oldWidget.userInfo.age) {
return true;
}
return false;
}
@override
bool updateShouldNotify(covariant UserInheritedModel oldWidget) {
// 基础更新判断(是否有任何变化)
return userInfo.name != oldWidget.userInfo.name ||
userInfo.age != oldWidget.userInfo.age;
}
}
// 4. 子Widget:只依赖name维度
class NameDisplay extends StatelessWidget {
const NameDisplay({super.key});
@override
Widget build(BuildContext context) {
final userInfo = UserInheritedModel.of(context, aspect: UserAspect.name)?.userInfo;
print('NameDisplay 重建了'); // 验证是否只在name变化时重建
return Text('姓名: ${userInfo?.name ?? "未知"}');
}
}
// 5. 子Widget:只依赖age维度
class AgeDisplay extends StatelessWidget {
const AgeDisplay({super.key});
@override
Widget build(BuildContext context) {
final userInfo = UserInheritedModel.of(context, aspect: UserAspect.age)?.userInfo;
print('AgeDisplay 重建了'); // 验证是否只在age变化时重建
return Text('年龄: ${userInfo?.age ?? 0}');
}
}
// 6. 用法示例
class InheritedModelDemo extends StatefulWidget {
const InheritedModelDemo({super.key});
@override
State<InheritedModelDemo> createState() => _InheritedModelDemoState();
}
class _InheritedModelDemoState extends State<InheritedModelDemo> {
late UserInfo userInfo;
@override
void initState() {
super.initState();
userInfo = UserInfo(name: "张三", age: 20);
}
void _updateName() {
setState(() {
userInfo = userInfo.copyWith(name: "李四");
});
}
void _updateAge() {
setState(() {
userInfo = userInfo.copyWith(age: 21);
});
}
@override
Widget build(BuildContext context) {
return UserInheritedModel(
userInfo: userInfo,
child: Scaffold(
appBar: AppBar(title: const Text('InheritedModel Demo')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
NameDisplay(),
SizedBox(height: 20),
AgeDisplay(),
],
),
),
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: _updateName,
child: const Icon(Icons.edit),
),
const SizedBox(width: 10),
FloatingActionButton(
onPressed: _updateAge,
child: const Icon(Icons.add),
),
],
),
),
);
}
}
关键点:
- 通过
dependencies
区分 Widget 关注的维度(UserAspect
)。 updateShouldNotifyDependent
精确控制某一维度变化时,只有依赖该维度的 Widget 才重建。
三、总结
类 | 核心能力 | 适用场景 |
---|---|---|
InheritedWidget |
基础跨层级数据共享 | 静态 / 低频变化数据(主题、用户信息) |
InheritedNotifier |
结合 Listenable 自动管理更新 |
高频变化数据(计数器、表单状态) |
InheritedModel |
按维度精确控制更新 | 多维度数据(需优化性能,避免无关 Widget 重建) |