Flutter InheritedWidget及扩展类InheritedNotifier、InheritedModel应用场景

在 Flutter 中,InheritedWidget 是实现 Widget 树中跨层级数据共享的核心机制,它解决了传统通过构造函数传递数据("prop drilling")的繁琐问题,尤其适合深层级 Widget 间的数据传递。其扩展类(InheritedNotifierInheritedModel 等)则在基础功能上增加了更精细的状态管理能力。

一、核心概念与关系

  • 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),
        ),
      ),
    );
  }
}

关键点:

  • 无需手动管理 updateShouldNotifyInheritedNotifier 会在 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 重建)
相关推荐
iceiceiceice3 小时前
iOS PDF阅读器段评实现:如何从 PDFSelection 精准还原一个自然段
前端·人工智能·ios
TT_Close3 小时前
【Flutter×鸿蒙】FVM 不认鸿蒙 SDK?4步手动塞进去
flutter·swift·harmonyos
雨白4 小时前
Android 快捷方式实战指南:静态、动态与固定快捷方式详解
android
hqk4 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
TT_Close5 小时前
【Flutter×鸿蒙】一个"插队"技巧,解决90%的 command not found
flutter·harmonyos
LING5 小时前
RN容器启动优化实践
android·react native
恋猫de小郭8 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker13 小时前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴13 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭1 天前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter