Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

3,061 阅读11分钟

开始介绍inheritedWidget之前,先来介绍一个 知识点 为后面的内容做铺垫

先介绍ancestorWidgetOfExactType

1. 先看下 Demo 代码结构

demo地址: github.com/LZQL/flutte…

可以说是目前 全网 最完整的demo演示了

2. ancestorWidgetOfExactType

返回给定类型的最近父widget,该widget的类型必须是具体widget的子类。

一般来说,inheritFromWidgetOfExactType更有用,因为继承的widget将在更改时触发消费者重新构建。ancestorWidgetOfExactType适用于交互事件处理程序(例如手势回调)或执行一次性任务,例如断言您拥有或不具有作为特定类型的父widgetwidget的构建方法的返回值不应该依赖于该方法返回的值,因为如果该方法的返回值发生更改,构建上下文将不会重新生成。这可能会导致生成方法中使用的数据发生更改,但是没有重新生成widget

总结一下上面的意思:

  1. ancestorWidgetOfExactType 一般用于 断言,是否有特定类型的父widget
  2. ancestorWidgetOfExactType可以用来获取父widget的一些信息
  3. 如果想要根据方法的返回值来判断是否重新构建,ancestorWidgetOfExactType并不适用

下面会分别给出 上面的3点总结来给出demo场景

1. 断言

这边就不给出自己的demo,直接看源码,源码的应用场景说明一切,这边也是官方翻译的最好证明

从上图可以看出,这是Hero的源码,做了断言,断言就写到这里

2. 获取父widget的一些信息

1. 代码结构

2. 运行效果

WidgeC是一个 加号按钮, 点击了WidgeC,获取HomepageState 调用incrementCounter 方法, , widgetAwidgetBwidgetC 会重新build,看下图

3. 具体代码

代码位置 ancestor01.dart

/// ancestorWidgetOfExactType 获取父widget的一些信息
class MyAncestorTree01 extends StatefulWidget {
  @override
  _MyAncestorTree01State createState() => _MyAncestorTree01State();
}

class _MyAncestorTree01State extends State<MyAncestorTree01> {
  @override
  Widget build(BuildContext context) {
    return TopPage01();
  }
}

class TopPage01 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Demo'),
        ),
        body: HomePage(),
      ),
    );
  }
}

class HomePage extends StatefulWidget {
  final HomePageState state = HomePageState();

  @override
  HomePageState createState() {
    return state;
  }
}

class HomePageState extends State<HomePage> {
  int counter = 0;

  void incrementCounter() {

    setState(() {
      counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          WidgetA(),
          WidgetB(),
          WidgetC(),
        ],
      ),
    );
  }
}

class WidgetA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    /// 获取 HomePageState 来获取 counter
    final HomePage widget =
        context.ancestorWidgetOfExactType(HomePage);
    final HomePageState state = widget?.state;

    return Center(
      child: Text(
        '${state == null ? 0 : state.counter}',
        style: Theme.of(context).textTheme.display1,
      ),
    );
  }
}

class WidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text('Widget  B  Text');
  }
}

class WidgetC extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    /// 获取 HomePageState 来 调用 加法操作
    final HomePage widget = context.ancestorWidgetOfExactType(HomePage);
    final HomePageState state = widget?.state;

    return RaisedButton(
      onPressed: () {
        state?.incrementCounter();
      },
      child: Icon(Icons.add),
    );
  }
}

3. 子widget无法检测到父widget的更改

demo 用来演示 子widget无法检测到父widget的更改 的具体情况 为后面的内容做铺垫 我将ancestorWidgetOfExactType封装了一个 of 方法放到了TopPage02里面, 与 2. 获取父widget 的一些信息 的使用场景不同。

1. 代码结构

2. 运行效果

注意看下图,当我点击了1 - AncestorWidgetOfExactType02 演示 按钮,进入 demo页面,从右侧可以看出,因为是第一次进去,所以全部widget都进行了build操作,但是当我 点击 了Add item按钮,TopPage02rebuild但是WidgetAWidgetBWidgetC,并不会进行rebuild

3. 具体代码

代码位置ancestor02.dart

/// ancestorWidgetOfExactType
/// 子widget无法检测到父widget的更改
/// (父widget rebuild 子widget no rebuild)
class MyAncestorTree02 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new TopPage02(
      child: new Scaffold(
        appBar: new AppBar(
          title: new Text('Title'),
        ),
        body: new Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            new WidgetA(),
            new WidgetB(),
            new WidgetC(),
          ],
        ),
      ),
    );
  }
}

class Item {
  String reference;

  Item(this.reference);
}

class TopPage02 extends StatefulWidget {
  TopPage02({
    Key key,
    this.child,
  }) : super(key: key);

  final Widget child;

  final TopPage02State state = new TopPage02State();

  @override
  TopPage02State createState() {
    return state;
  }

  static TopPage02State of(BuildContext context) {
    /// 通过从 TopPage02 的 context 得到树结构来返回第一个 TopPage02State
    return (context.ancestorWidgetOfExactType(TopPage02)
            as TopPage02)
        .state;

  }
}

class TopPage02State extends State<TopPage02> {

  List<Item> _items = <Item>[];

  int get itemsCount => _items.length;

  void addItem(String reference) {
    setState(() {
      _items.add(new Item(reference));
    });
  }

  @override
  Widget build(BuildContext context) {
    return widget.child;
  }
}

class WidgetA extends StatefulWidget {
  @override
  _WidgetAState createState() => _WidgetAState();
}

class _WidgetAState extends State<WidgetA> {
  @override
  Widget build(BuildContext context) {
    final TopPage02State state = TopPage02.of(context);
    return new Center(
      child: new RaisedButton(
        child: new Text('WidgetA :Add Item'),
        onPressed: () {
          /// 这边调用 addItem 方法,但是WidgetA,WidgetB,WidgetC
          /// 并不会 build
          /// 这就说明了:widget的构建方法的返回值不应该依赖于该方法返回的值,
          /// 因为如果该方法的返回值发生更改,构建上下文将不会重新生成。
          /// 这可能会导致生成方法中使用的数据发生更改,但是没有重新生成widget
          state.addItem('new item');
        },
      ),
    );
  }
}

class WidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final TopPage02State state = TopPage02.of(context);
    return new Text('widgetB itemCount:${state.itemsCount}');
  }
}

class WidgetC extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Text('I am Widget C');
  }
}

3. InheritedWidget

1. 什么是 InheritedWidget

特性:

  1. InheritedWidget是一个可以在树中高效地向下传递数据的组件:我们可以在以InheritedWidget 为节点的树下任一Widget中调用 BuildContext.inheritFromWidgetOfExactType 来获取离其最近的 InheritedWidget实例
  2. 当以上面这种方式(调用inheritFromWidgetOfExactType方法时)被引用后,每当InheritedWidget自身的状态改变时,会导致 “consumer”(调用inheritFromWidgetOfExactType方法的这个Child) 重新build

第一点:在Flutter中,正是通过InheritedWidget来共享应用主题(Theme)和Locale(当前语言环境)信息的 第二点:解决了 上面提到ancestorWidgetOfExactType 的第三点不能通过返回值来进行重新build的情况

InheritedWidget的在Widget树中数据传递方向是从上到下的,这和Notification的传递方向正好相反。(后面系列文章介绍Notification)

2. didChangeDependencies

StatefulWidgetState对象有一个回调didChangeDependencies,它会在“依赖”发生变化时被Flutter Framework调用。而这个“依赖”指的就是是否使用了父widgetInheritedWidget的数据,如果使用了,则代表有依赖,如果没有使用则代表没有依赖。这种机制可以使子组件在所依赖的主题、locale等发生变化时有机会来做一些事情。

4. 通过 2 - InheritedWidget演示01 ,发现问题

这个例子 是参照 book.flutterchina.club/chapter7/in… 写的一样,相信很多人都看过

1. 代码结构

2. 效果图

当我点击了 click me按钮 加1,widgetAwidgeB,RaisedButton会重新build

3. 代码

代码位置:inheritedwidget01.dart

/// InheritedWidget01 , 会导致 `widgetA`` widgeB`,`RaisedButton `会重新`build`
  class InheritedWidgetTest01 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return InheritedWidgetTest01State();
  }
}

class InheritedWidgetTest01State extends State<InheritedWidgetTest01> {
  int tmpData = 0;

  @override
  Widget build(BuildContext context) {
    print('InheritedWidgetTest01 build');
    return Scaffold(
      body: Center(
        child: ShareInherited(
          data: tmpData,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              WidgetA(),
              WidgetB(),
              RaisedButton(
                child: Text("Click me"),
                onPressed: () {
                  setState(() {
                    print('onPressed');
                    tmpData += 1;
                  });
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class ShareInherited extends InheritedWidget {
  final int data; //需要在子树中共享的数据,保存点击次数

  ShareInherited({@required this.data, @required Widget child}) : super(child: child) {
    print('ShareInherited construct');
  }

  /// 允许所有子 widget 通过包含的 context 获得最近的 ShareInherited 实例
  /// 定义一个便捷方法,方便子树中的widget获取共享数据
  /// 在内部,除了简单地返回 ShareInherited 实例外,它还订阅消费者 widget 以便用于通知更改
  static ShareInherited of(BuildContext context) {
    return context.inheritFromWidgetOfExactType(ShareInherited);
  }

  /// 用来告诉 InheritedWidget 如果对数据进行了修改,
  /// 是否必须将通知传递给所有子 widget(已注册/已订阅)
  @override
  bool updateShouldNotify(ShareInherited oldWidget) {
    // 如果返回true,则子树中依赖(build函数中有调用)本widget
    // 的子widget的`state.didChangeDependencies`会被调用
    bool result = oldWidget.data != this.data;
    print('ShareInherited updateShouldNotify result = $result');
    return result;
  }
}

class WidgetA extends StatefulWidget {
  @override
  _WidgetAState createState() => _WidgetAState();
}

class _WidgetAState extends State<WidgetA> {
  @override
  Widget build(BuildContext context) {
    print('WidgetA build');
    int data = ShareInherited.of(context).data;
    return Text('WidgetA data = $data');
  }

  @override
  void didChangeDependencies() {
    print('WidgetA didChangeDependencies');
    super.didChangeDependencies();
  }
}

class WidgetB extends StatefulWidget {
  @override
  _WidgetBState createState() => _WidgetBState();
}

class _WidgetBState extends State<WidgetB> {
  @override
  Widget build(BuildContext context) {
    print('WidgetB build');
    return Text('WidgetB');
  }

  @override
  void didChangeDependencies() {
    print('WidgetB didChangeDependencies');
    super.didChangeDependencies();
  }
}

4. 发现的现象

WidgetA调用了inheritFromWidgetOfExactType方法,获得了存放在 ShareInherited对象里的data数据并显示在WidgetA内容上,同时使得 WidgetAShareInherited产生关联;

当点击 RaisedButton触发InheritedWidgetTest01状态更新时,InheritedWidgetTest01Statebuild 方法回调,重新构建 ShareInherited对象传入新值,由于data发生变化,ShareInherited的方法updateShouldNotify中返回了true,最终使得与ShareInherited关联的WidgetA触发reBuild

当我们运行并点击RaisedButton后,页面表现得确实如上述所示,WidgetA的内容由 WidgetA data = 0变为了WidgetA data = 1,似乎 InheritedWidget 正确的使用方式正是如此,但是log里输出的却是如下:

I/flutter (11303): onPressed
I/flutter (11303): InheritedWidgetTest01 build
I/flutter (11303): ShareInherited construct
I/flutter (11303): ShareInherited updateShouldNotify result = true
I/flutter (11303): WidgetA didChangeDependencies
I/flutter (11303): WidgetA build
I/flutter (11303): WidgetB build

可以看到,结合前面的代码逻辑分析,理论上只有 WidgetA 才会reBuild,而现在却产生了I/flutter (11303): WidgetB build这条记录。这是为什么呢?

5. 原因分析

其实可以从前面提到的特性2找到答案。其中说到:InheriteWidget状态发生变化时会rebuild相关的child。 我们知道,flutterWidget被标识为了@immutable,即是不可变的,那么所谓的状态发生变化就意味着InheriteWidget重新构建,由于前面代码中在InheriteWidget构造时同时也构造的其child对象,因此当InheriteWidget重新构建时也会导致child跟着重新构建,这样也就失去了“rebuild相关的child”的意义,

也就是说,要想特性2生效,需要保证InheriteWidget节点下的树不会被重新构建。

5. 解决方法1:使用 const Widget

InheriteWidgetchild转化为const,这样即使在重建 InheriteWidget时,由于其child得到的是同一个对象,也就不会导致这个子树重建,选择性reBuild也就得到了保证。但是由于const特性,相关的参数也必须是常量,因此需要重写或修改的代码量相对较多,因此更推荐解决方法2的做法,这个方法在后面回写

1. const demo 01,发现问题

1. 代码结构

2. 效果图

WidgeAWidgeBFlatButton是处于同一级别的

从下图可以看到 当我点击了click mewidgetB并不会被 rebuild, 但是 WidgeAFlatButtonrebuild,这样解决了WidgeB rebuild的问题,但是 FlateButton 并不涉及到 页面的数据刷新,如果我想要让 FlatButton也不rebuild呢? 看constdemo02

3. 代码

代码位置:inheritedwidget_const_01.dart

/// 使用 const
/// Widget A ,FlatButton rebuild, Widget B  no rebuild
class InheritedWidgetConst01 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return InheritedWidgetConst01State();
  }
}

class InheritedWidgetConst01State extends State<InheritedWidgetConst01> {
  int tmpData = 0;



  @override
  Widget build(BuildContext context) {
    print('InheritedWidgetTest02 build');
    return Scaffold(
      body: Center(
        child: ShareInherited(
          data: tmpData,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const WidgetA(),
              const WidgetB(),
              FlatButton(
                child: Text("Click me"),
                onPressed: () {
                  setState(() {
                    print('onPressed');
                    tmpData += 1;
                  });
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class ShareInherited extends InheritedWidget {
  final int data;

  ShareInherited({this.data, @required Widget child}) : super(child: child) {
    print('ShareInherited construct');
  }

  @override
  bool updateShouldNotify(ShareInherited oldWidget) {
    bool result = oldWidget.data != this.data;
    print('ShareInherited updateShouldNotify result = $result');
    return result;
  }

  static ShareInherited of(BuildContext context) {
    return context.inheritFromWidgetOfExactType(ShareInherited);
  }
}

class WidgetA extends StatelessWidget {

  const WidgetA();

  @override
  Widget build(BuildContext context) {
    print('WidgetA build');
    int data = ShareInherited.of(context).data;
    return Text('WidgetA data = $data');
  }
}

class WidgetB extends StatelessWidget {

  const WidgetB();

  @override
  Widget build(BuildContext context) {
    print('WidgetB build');
    return Text('WidgetB');
  }
}

2. const demo 02,继续发现问题

1. 代码结构

2. 效果图

你会发现,WidgeAWidgeC还是rebuild , 要解决这个问题,就需要用到 文章顶部提到的ancestorWidgetOfExactType了,看 const demo 03,终极写法

3. 代码

代码位置 inheritedwidget_const_02.dart

/// 使用 const
/// Widget A ,Widget C  rebuild, Widget B  no rebuild
class InheritedWidgetConst02 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return InheritedWidgetConst02State();
  }
}

class InheritedWidgetConst02State extends State<InheritedWidgetConst02> {
  int tmpData = 0;

  void addItem(){
    setState(() {
      tmpData++;
    });
  }

  @override
  Widget build(BuildContext context) {
    print('InheritedWidgetTest02 build');
    return Scaffold(
      body: Center(
        child: ShareInherited(
          data: tmpData,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const WidgetA(),
              const WidgetB(),
              WidgetC(),
            ],
          ),
          state: this,
        ),
      ),
    );
  }
}

class ShareInherited extends InheritedWidget {
  final int data;
  final InheritedWidgetConst02State state;
  ShareInherited({this.data, @required Widget child,this.state}) : super(child: child) {
    print('ShareInherited construct');
  }

  @override
  bool updateShouldNotify(ShareInherited oldWidget) {
    bool result = oldWidget.data != this.data;
    print('ShareInherited updateShouldNotify result = $result');
    return result;
  }

  static ShareInherited of(BuildContext context) {
    return context.inheritFromWidgetOfExactType(ShareInherited);
  }
}

class WidgetA extends StatelessWidget {

  const WidgetA();

  @override
  Widget build(BuildContext context) {
    print('WidgetA build');
    int data = ShareInherited.of(context).data;
    return Text('WidgetA data = $data');
  }
}

class WidgetB extends StatelessWidget {

  const WidgetB();

  @override
  Widget build(BuildContext context) {
    print('WidgetB build');
    return Text('WidgetB');
  }
}



class WidgetC extends StatefulWidget {
  @override
  _WidgetCState createState() => _WidgetCState();
}

class _WidgetCState extends State<WidgetC> {
  @override
  Widget build(BuildContext context) {
    print('Widge C build');
    InheritedWidgetConst02State state = ShareInherited.of(context).state;

    return FlatButton(
      child: Text("Click me"),
      onPressed: () {
        setState(() {
          print('onPressed');
          state.addItem();
        });
      },
    );
  }
}

3. const demo 03,终极写法

1. 代码结构

2. 效果图

ShareInheritedof方法 ,增加了 是否 rebuild的参数 你会发现 ,现在只有WidgeArebuild ,完美啊

  static ShareInherited of([BuildContext context, bool rebuild = true]) {
    return (rebuild
        ? context.inheritFromWidgetOfExactType(ShareInherited)
        : context.ancestorWidgetOfExactType(ShareInherited) );
  }

3. 代码

代码位置inheritedwidget_const_03.dart

/// 使用 const
/// Widget A rebuild, Widget B Widget C no rebuild
class InheritedWidgetConst03 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return InheritedWidgetConst03State();
  }
}

class InheritedWidgetConst03State extends State<InheritedWidgetConst03> {
  int tmpData = 0;

  void addItem() {
    setState(() {
      tmpData++;
    });
  }

  @override
  Widget build(BuildContext context) {
    print('InheritedWidgetTest02 build');
    return Scaffold(
      body: Center(
        child: ShareInherited(
          data: tmpData,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const WidgetA(),
              const WidgetB(),
              const WidgetC(),
            ],
          ),
          state: this,
        ),
      ),
    );
  }
}

class ShareInherited extends InheritedWidget {
  final int data;
  final InheritedWidgetConst03State state;

  ShareInherited({this.data, @required Widget child, this.state})
      : super(child: child) {
    print('ShareInherited construct');
  }

  @override
  bool updateShouldNotify(ShareInherited oldWidget) {
    bool result = oldWidget.data != this.data;
    print('ShareInherited updateShouldNotify result = $result');
    return result;
  }

  static ShareInherited of([BuildContext context, bool rebuild = true]) {
    return (rebuild
        ? context.inheritFromWidgetOfExactType(ShareInherited)
        : context.ancestorWidgetOfExactType(ShareInherited) );
  }
}

class WidgetA extends StatelessWidget {

  const WidgetA();

  @override
  Widget build(BuildContext context) {
    print('WidgetA build');
    int data = ShareInherited
        .of(context)
        .data;
    return Text('WidgetA data = $data');
  }
}

class WidgetB extends StatelessWidget {

  const WidgetB();

  @override
  Widget build(BuildContext context) {
    print('WidgetB build');
    return Text('WidgetB');
  }
}

class WidgetC extends StatelessWidget {
  const WidgetC();
  @override
  Widget build(BuildContext context) {
    print('Widge C build');
    InheritedWidgetConst03State state = ShareInherited.of(context,false).state;

    return FlatButton(
      child: Text("Click me"),
      onPressed: () {
        print('onPressed');
        state.addItem();
      },
    );
  }
}

6. 解决方法2:上移Child对象到InheriteWidgetParent Widget

1. out demo 01,发现问题

1. 代码结构

2. 效果图

具体看代码吧,稍显复杂 ,这边命名不是很规范,懒得改了, 太累了写demo,看代码可以知道

class ShareInherited extends StatelessWidget

这里的ShareInherited 是一个 StatelessWidget ,也就是 上移了Child对象到InheriteWidgetParent Widget

class _ShareInherited extends InheritedWidget

_ShareInherited 才是 具体的 InheritedWidget

看下图可知 Widget A ,FlatButton rebuild, Widget B no rebuild

这时候我们 一样的 把 FlatButton 放到 WidgetC 然后上移到 InheriteWidgetParent Widget 看能不能实现让 WidgeC no rebuild

3. 代码

代码位置inheritedwidget_out_01.dart

/// 上移`Child`对象到`InheriteWidget``Parent Widget`
/// Widget A ,FlatButton rebuild, Widget B  no rebuild
class InheritedWidgetOut01 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return InheritedWidgetOut01State();
  }
}

class InheritedWidgetOut01State extends State<InheritedWidgetOut01> {
  @override
  Widget build(BuildContext context) {

    return Scaffold(
      body: MyWidget(
          Column(
            children: <Widget>[
              WidgetA(),
              WidgetB()
            ],
          )
      ),
    );
  }
}

class MyWidget extends StatefulWidget {

  final Widget child;
  MyWidget(this.child);

  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {

  int tempData = 0;

  @override
  Widget build(BuildContext context) {
    return ShareInherited(
      data: tempData,
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            widget.child,
            FlatButton(
                  child: Text("Click me"),
                  onPressed: () {
                    setState(() {
                      print('onPressed');
                      tempData += 1;
                    });
                  },
                )
          ],
        ),
      ),
    );
  }
}

class ShareInherited extends StatelessWidget {
  final int data;
  final Widget child;


  ShareInherited({
    Key key,
    this.data,
    this.child
  }): assert(child != null),
        assert(data != null),
        super(key: key);

  static int of(BuildContext context) {
    final _ShareInherited inheritedTheme = context.inheritFromWidgetOfExactType(_ShareInherited);
    return inheritedTheme.shareInherited.data;
  }

  @override
  Widget build(BuildContext context) {
    return _ShareInherited(shareInherited:this , child: child,);
  }
}

class _ShareInherited extends InheritedWidget{

  final ShareInherited shareInherited;

  _ShareInherited({
    Key key,
    @required this.shareInherited,
    @required Widget child,
  }):assert(shareInherited != null),
  super(key: key, child: child);

  @override
  bool updateShouldNotify(_ShareInherited oldWidget) {
    return shareInherited.data != oldWidget.shareInherited.data;
  }

}

class WidgetA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('WidgetA build');
    int data = ShareInherited.of(context);
    return Text('WidgetA data = $data');
  }
}

class WidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('WidgetB build');
    return Text('WidgetB');
  }
}

2. out demo 02,继续发现问题

1. 代码结构

2. 效果图

你会发现 Widget A ,Widget C rebuild, Widget B no rebuild

如果想要 让 Widge C no rebuild,看out demo 03

3. 代码

代码位置inheritedwidget_out_02.dart

/// 上移`Child`对象到`InheriteWidget``Parent Widget`
/// Widget A ,Widget C  rebuild, Widget B  no rebuild
class InheritedWidgetOut02 extends StatefulWidget {
  @override
  _InheritedWidgetOut02State createState() => new _InheritedWidgetOut02State();
}

class _InheritedWidgetOut02State extends State<InheritedWidgetOut02> {
  @override
  Widget build(BuildContext context) {
    return new MyInheritedWidget(
      child: new Scaffold(
        appBar: new AppBar(
          title: new Text('Title'),
        ),
        body: Center(
          child: new Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[new WidgetA(), new WidgetB(), new WidgetC()],
          ),
        ),
      ),
    );
  }
}

class MyInheritedWidget extends StatefulWidget {
  MyInheritedWidget({
    Key key,
    this.child,
  }) : super(key: key);

  final Widget child;

  @override
  MyInheritedWidgetState createState() => new MyInheritedWidgetState();

  static MyInheritedWidgetState of([BuildContext context]) {
    return (context.inheritFromWidgetOfExactType(_MyInherited) as _MyInherited).data;
    // 通过从 MyInheritedWidget 的 context 得到树结构来返回第一个 MyInheritedWidgetState
  }
}

class MyInheritedWidgetState extends State<MyInheritedWidget> {

  int tempData = 0;

  /// Helper method to add an Item
  void addItem() {
    setState(() {
      tempData++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new _MyInherited(
      data: this,
      child: widget.child,
    );
  }
}

class _MyInherited extends InheritedWidget {
  _MyInherited({
    Key key,
    @required Widget child,
    @required this.data,
  }) : super(key: key, child: child);

  final MyInheritedWidgetState data;

  @override
  bool updateShouldNotify(_MyInherited oldWidget) {
    return true;
  }
}

class WidgetA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('Widget A build');
    final MyInheritedWidgetState state = MyInheritedWidget.of(context);
    return Text('WidgetA data = ${state.tempData}');
  }
}

class WidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('Widget B build');
    return Text('WidgetB');
  }
}

class WidgetC extends StatefulWidget {
  @override
  _WidgetCState createState() => _WidgetCState();
}

class _WidgetCState extends State<WidgetC> {
  @override
  Widget build(BuildContext context) {
    print('Widget C build');
    final MyInheritedWidgetState state = MyInheritedWidget.of(context);
    return RaisedButton(
      child: Text("Click me"),
      onPressed: () {
        print('onPressed');
        state.addItem();
      },
    );
  }
}

3. out demo 03,终极写法

1. 代码结构

2. 效果图

因为这个demoPerfomance 界面展示不够形象,就直接展示输出log查看结果比较形象

可以发现 Widget A rebuild, Widget B Widget C no rebuild ,完美啊 ,写到这里已经要吐了

3. 代码

代码位置inheritedwidget_out_03.dart

/// 上移`Child`对象到`InheriteWidget``Parent Widget`
/// Widget A rebuild, Widget B Widget C no rebuild
class InheritedWidgetOut03 extends StatefulWidget {
  @override
  _InheritedWidgetOut03State createState() => new _InheritedWidgetOut03State();
}

class _InheritedWidgetOut03State extends State<InheritedWidgetOut03> {
  @override
  Widget build(BuildContext context) {
    return new MyInheritedWidget(
      child: new Scaffold(
        appBar: new AppBar(
          title: new Text('Title'),
        ),
        body: Center(
          child: new Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[new WidgetA(), new WidgetB(), new WidgetC()],
          ),
        ),
      ),
    );
  }
}

class MyInheritedWidget extends StatefulWidget {
  MyInheritedWidget({
    Key key,
    this.child,
  }) : super(key: key);

  final Widget child;

  @override
  MyInheritedWidgetState createState() => new MyInheritedWidgetState();

  static MyInheritedWidgetState of(
      [BuildContext context, bool rebuild = true]) {
    return (rebuild
            ? context.inheritFromWidgetOfExactType(_MyInherited) as _MyInherited
            : context.ancestorWidgetOfExactType(_MyInherited) as _MyInherited)
        .data;
    // 通过从 MyInheritedWidget 的 context 得到树结构来返回第一个 MyInheritedWidgetState
  }
}

class MyInheritedWidgetState extends State<MyInheritedWidget> {

  int tempData = 0;

  /// Helper method to add an Item
  void addItem() {
    setState(() {
      tempData++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new _MyInherited(
      data: this,
      child: widget.child,
    );
  }
}

class _MyInherited extends InheritedWidget {
  _MyInherited({
    Key key,
    @required Widget child,
    @required this.data,
  }) : super(key: key, child: child);

  final MyInheritedWidgetState data;

  @override
  bool updateShouldNotify(_MyInherited oldWidget) {
    return true;
  }
}

class WidgetA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('Widget A build');
    final MyInheritedWidgetState state = MyInheritedWidget.of(context);
    return Text('WidgetA data = ${state.tempData}');
  }
}

class WidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('Widget B build');
    return Text('WidgetB');
  }
}

class WidgetC extends StatefulWidget {
  @override
  _WidgetCState createState() => _WidgetCState();
}

class _WidgetCState extends State<WidgetC> {
  @override
  Widget build(BuildContext context) {
    print('Widget C build');
    final MyInheritedWidgetState state = MyInheritedWidget.of(context, false);
    return RaisedButton(
      child: Text("Click me"),
      onPressed: () {
        print('onPressed');
        state.addItem();
      },
    );
  }
}

7. 两种解决方法,在源码中的应用

方法1 : 可以查看TickerMode这个类

方法2: 可以查看 Theme

8. 参考文章

book.flutterchina.club/chapter7/in…

qiita.com/ko2ic/items…

juejin.cn/post/684490…

linjiang.tech/2019/02/25/…

扫一扫,关注我的微信公众号
都是一些个人学习笔记

点击下面阅读原文,用电脑看,有目录,更舒服哦