本篇文章主要介绍Flutter中的InheritedWidget小部件,以及其官方小部件库中的应用。

官方介绍

关于InheritedWidget,在官方文档中是这样描述的:

  • 1,能够沿着树向下传递信息。
  • 2,能够运用 BuildContext.dependOnInheritedWidgetOfExactType方法,获取最近的指定类型的inherited widget
  • 3,当inherited widget状况产生改动时,所有依靠其状况的子部件都会进行rebuild

咱们该如何了解InheritedWidget呢,接下来,经过几个示例来阐述InheritedWidget

ThemeData

咱们常常运用的ThemeData便是一个inheritedWidget,一般咱们Approot MaterialApp,这样咱们的ThemeDataWidget树的最顶端。

咱们能够运用

final themeData = Theme.of(context);

来获取当前的主题,当主题改动时,会从Widget树的最顶端,沿着树,从上到下,顺次改写每个依靠themeData的子部件。

static ThemeData of(BuildContext context) {
  final _InheritedTheme? inheritedTheme = context.dependOnInheritedWidgetOfExactType<_InheritedTheme>();
  final MaterialLocalizations? localizations = Localizations.of<MaterialLocalizations>(context, MaterialLocalizations);
  final ScriptCategory category = localizations?.scriptCategory ?? ScriptCategory.englishLike;
  final ThemeData theme = inheritedTheme?.theme.data ?? _kFallbackTheme;
  return ThemeData.localize(theme, theme.typography.geometryThemeFor(category));
}

static ThemeData of(BuildContext context)的实现咱们能够看出其是一个InheritedWidget

示例

无状况InheritedWidget

对于无状况的InheritedWidget,咱们以读取其同享的数据为例展开,接下来,咱们新建Counter

class Counter extends InheritedWidget { // 1
    const Counter( {Key? key,  required this.child, required this.counter})
      : super(key: key, child: child); // 2
  final int counter;
  final Widget child;
  static Counter? of(BuildContext context) { // 3
    return context.dependOnInheritedWidgetOfExactType<Counter>();
  }
  @override
  bool updateShouldNotify(covariant Counter oldWidget) { // 4
    return oldWidget.counter != counter;
  }
}
  • 1,Counter继承InheritedWidget
  • 2,在构建时,需求供给counter值和子Widget
  • 3,向子部件供给获取状况的接口。
  • 4,是否告诉子部件进行状况改写。

咱们能够这样运用该InheritedWidget

Widget buildInheritedWidget(BuildContext context) {
  return Counter(
      counter: 5,
      child: Scaffold(
        appBar: AppBar(),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Text(
                'You have pushed the button this many times:',
              ),
              WidgetE(),
            ],
          ),
        ),
      ));
}
@override
Widget build(BuildContext context) {
  return buildInheritedWidget(context);
}

运转结果如下

理解InheritedWidget及应用

接下来,咱们创立一个有状况的InheritedWidget

有状况的InheritedWidget

1,创立一个持有状况的InheritedWidget

class CounterWidget extends InheritedWidget {
  const CounterWidget(
      {Key? key,
        required this.counter,
        required this.child,
        required this.data})
      : super(child: child, key: key);
  final int counter;
  final Widget child;
  final CounterWrapperState data; // 1
  /// 获取 CounterWidget 实例
  static CounterWidget? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<CounterWidget>();
  }
  @override
  bool updateShouldNotify(covariant CounterWidget oldWidget) {
    // TODO: implement updateShouldNotify
    return oldWidget.counter != counter;
  }
}
  • 1,比较于无状况的,这儿新增了一个CounterWrapperState

解下来,创立一个StatefulWidget,并将CounterWidget作为该部件的子部件。

class CounterWrapper extends StatefulWidget {
  final Widget child; // 1
  const CounterWrapper({Key? key, required this.child}) : super(key: key);
  static CounterWrapperState of(BuildContext context, {bool build = true}) { // 2
    return build
        ? (context.dependOnInheritedWidgetOfExactType<CounterWidget>())!.data
        : context.findAncestorWidgetOfExactType<CounterWidget>()!.data;
  }
  @override
  CounterWrapperState createState() => CounterWrapperState();
}
class CounterWrapperState extends State<CounterWrapper> {
  int counter = 0;
  void incrementCounter() { // 3
    setState(() {
      counter++;
    });
  }
  @override
  Widget build(BuildContext context) { // 4
    return CounterWidget(data: this, counter: counter, child: widget.child);
  }
}
  • 1,在构建时,需供给child,并传递给CounterWidget

  • 2,供给获取状况的接口,有两种方式 : 当运用dependOnInheritedWidgetOfExactType时,当状况改动时,会从头rebuild子部件。 运用findAncestorWidgetOfExactType时,当状况改动时,子部件不会改写。

  • 3,计数器加1,改写Widget。

  • 4,将CounterWidget作为CounterWrapper的子部件。

子Widget改写、部分改写、不改写

接下来,创立5个不同的Widget:

/// 使计数状况改动
class WidgetA extends StatefulWidget {
  const WidgetA({Key? key}) : super(key: key);
  @override
  _WidgetAState createState() => _WidgetAState();
}
class _WidgetAState extends State<WidgetA> {
  @override
  Widget build(BuildContext context) {
    print("A refresh");
    return ElevatedButton(onPressed: onPressed, child: Text("Increment"));
  }
  onPressed() {
    CounterWrapperState wrapper = CounterWrapper.of(context, build: false);
    wrapper.incrementCounter();
  }
}
/// 部分改写
class WidgetB extends StatelessWidget {
  const WidgetB({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    print("widget B 整个 改写");
    return Builder(builder: (contextTwo) {
      print("widget B Text 部分改写");
      final CounterWrapperState state =
      CounterWrapper.of(contextTwo, build: true);
      return Text('${state.counter}');
    });
  }
}
/// inheritedWidget改写时,也改写
class WidgetC extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final CounterWrapperState state =
    CounterWrapper.of(context, build: true);
    print("widget C 改写");
    return new Text('I am Widget C ${state.counter}');
  }
}
/// inheritedWidget改写时,不改写
class WidgetC1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final CounterWrapperState state =
    CounterWrapper.of(context, build: false);
    print("widget C1 改写");
    return new Text('I am Widget C1 ${state.counter}');
  }
}
/// 不依靠inheriteWidget状况的子部件
class WidgetD extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("widget D 改写");
    return new Text('I am Widget D');
  }
}
  • 1,WidgetA: 使 CounterWrapper 的状况改动。
  • 2,WidgetB: 不改写整个页面,对依靠部分进行部分改写
  • 3,WidgetC: 依靠inheritedWidget的状况,状况改动时,也随之改写。
  • 4,WidgetC1: 只在初始化时,获取inheritedWidget的状况,不随之改写。
  • 5,WidgetD: inheritedWidget的子部件,但不依靠其状况

咱们将这些Widget加载到视图中

Widget buildStatefulInheritedWidget(BuildContext context) {
  return CounterWrapper(
      child: Scaffold(
        appBar: AppBar(),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Text(
                'You have pushed the button this many times:',
              ),
              WidgetB(),
              WidgetA(),
              WidgetC(),
              WidgetC1(),
              WidgetD(),
            ],
          ),
        ),
      ));
}

界面如下

理解InheritedWidget及应用

点击increment,只会有 WidgetCWidgetB 进行改写。

flutter: widget C 改写
flutter: widget B Text 部分改写

理解InheritedWidget及应用

这样咱们就能够界说咱们自己的inheritedWidget,并告诉其子部件进行数据改写。

总结

咱们能够运用InheritedWidget同享大局状况,子部件能够获取其状况,并控制小部件改写

最终附上本文涉及的示例代码 inherited_widget_demo

假如觉得有收成请按如下方式给个 爱心三连::点个赞鼓励一下。:收藏文章,便利回看哦!。:谈论沟通,相互前进!