數(shù)據(jù)傳遞/狀態(tài)管理 一InheritedWidget

數(shù)據(jù)傳遞/狀態(tài)管理 一InheritedWidget

InheritedWidget是一個(gè)特殊的widget,可以存儲(chǔ)和獲取數(shù)據(jù),子組件可以獲取到存儲(chǔ)的數(shù)據(jù),常用的 MediaQuery、Theme 就是繼承了 InheritedWidget。先通過(guò)MediaQuery來(lái)學(xué)習(xí)InheritedWidget。

  • MediaQuery
class MediaQuery extends InheritedWidget {
    const MediaQuery({
      Key key,
      @required this.data,
      @required Widget child,
    }) : assert(child != null),
         assert(data != null),
         super(key: key, child: child);
  
    ///...
    final MediaQueryData data;
    ///...
  
    static MediaQueryData of(BuildContext context, { bool nullOk = false }) {
    ///...
  }
}

通過(guò) MediaQuery.of(context) 獲取到MediaQueryData對(duì)象,然后獲取到設(shè)備屏幕相關(guān)的信息。

///獲取屏幕寬度
MediaQuery.of(context).size.width;

代碼查找,下面這些地方創(chuàng)建了MediaQuery

WX20190615-113309@2x

在app.dart里面可以發(fā)現(xiàn) WidgetsApp 如下代碼,build 方法返回一個(gè)DefaultFocusTraversal組件,而DefaultFocusTraversal 組件的 child 就是 MediaQuery。

@override
Widget build(BuildContext context) {
    ///...
  return DefaultFocusTraversal(
    policy: ReadingOrderTraversalPolicy(),
    child: MediaQuery(
      data: MediaQueryData.fromWindow(WidgetsBinding.instance.window),
      child: Localizations(
        locale: appLocale,
        delegates: _localizationsDelegates.toList(),
        child: title,
      ),
    ),
  );
}

繼續(xù)通過(guò)代碼查找在 MaterialApp 的源碼里面找到了 WidgetsApp ,在build方法里面返回了ScrollConfiguration類,ScrollConfigurationchild就是WidgetsApp

@override
Widget build(BuildContext context) {
  Widget result = WidgetsApp(
    key: GlobalObjectKey(this),
    navigatorKey: widget.navigatorKey,
    navigatorObservers: _navigatorObservers,
      pageRouteBuilder: <T>(RouteSettings settings, WidgetBuilder builder) =>
          MaterialPageRoute<T>(settings: settings, builder: builder),
    home: widget.home,
  ///...
  );
   
  return ScrollConfiguration(
    behavior: _MaterialScrollBehavior(),
    child: result,
  );
}

通過(guò)這些代碼,可以推斷出 MaterialApphome是屬于MediaQuery的子組件,所有home下面所有組件都能夠通過(guò) MediaQuery.of(context) 來(lái)獲取其共享的數(shù)據(jù)。但是注意并不是任何組件的任何地方,只有當(dāng)前組件執(zhí)行完 didChangeDependencies 方法之后才能正確的獲取到 InheritedWidget 對(duì)象的數(shù)據(jù)。

  • 示例

    完成下面的示例,頁(yè)面進(jìn)來(lái)加載用戶信息,保存和展示,然后在另外的頁(yè)面修改編輯后返回,展示的數(shù)據(jù)也改變了:

Jun-15-2019 13-16-35

完成上面的示例首先創(chuàng)建一個(gè)數(shù)據(jù)實(shí)體類,

///共享的數(shù)據(jù)
class InheritedWidgetData {
  String userName;
  int userAge;

  InheritedWidgetData({this.userName = "", this.userAge = 0});

  void setUser(String userName, int userAge) {
    this.userName = userName;
    this.userAge = userAge;
  }
}

InheritedWidgetDemo 繼承 InheritedWidgetdata 存放著用戶的數(shù)據(jù)。提供一個(gè)of的靜態(tài)方法供子組件調(diào)用,復(fù)寫updateShouldNotify 方法判斷是否需要更新。

///主Widget 繼承InheritedWidget 存放數(shù)據(jù)
class InheritedWidgetDemo extends InheritedWidget {
  final InheritedWidgetData data;

  InheritedWidgetDemo({@required this.data, @required Widget child})
      : super(child: child);

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

  static InheritedWidgetData of(BuildContext context) {
    final InheritedWidgetDemo user =
        context.inheritFromWidgetOfExactType(InheritedWidgetDemo);
    return user.data;
  }
}

數(shù)據(jù)展示W(wǎng)idget,在 didChangeDependencies 方法里面獲取用戶數(shù)據(jù)。頁(yè)面初始化開啟模擬網(wǎng)絡(luò)請(qǐng)求等待3秒后,調(diào)用 setUser 方法修改 InheritedWidgetDemo 中的數(shù)據(jù),然后重建界面。當(dāng)用戶信息為空的話頁(yè)面顯示加載等待組件。

class CenterWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _CenterWidgetState();
}

class _CenterWidgetState extends State<CenterWidget> {
  InheritedWidgetData _userData;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _userData = InheritedWidgetDemo.of(context);
     _getUserData();
  }

  _getUserData() async {
    ///模擬網(wǎng)絡(luò)請(qǐng)求 等待五秒
    await Future.delayed(Duration(seconds: 3));
    InheritedWidgetDemo.of(context).setUser("李華", 18);
    ///setState 觸發(fā)頁(yè)面刷新
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return new Center(
      /// 數(shù)據(jù)為空顯示加載圓圈
      child: _userData.userName == ""
          ? CircularProgressIndicator()
          : new UserInfoWidget(),
    );
  }
}

用戶信息展示W(wǎng)idget,和上面的Widget一樣,在 didChangeDependencies 方法里面獲取用戶數(shù)據(jù)并且展示。

///用戶信息Widget
class UserInfoWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _UserInfoState();
}

class _UserInfoState extends State<UserInfoWidget> {
  InheritedWidgetData _userData;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _userData = InheritedWidgetDemo.of(context);
  }

  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new Column(
        mainAxisAlignment: MainAxisAlignment.center,
        mainAxisSize: MainAxisSize.max,
        children: <Widget>[
          new Text(_userData.userName),
          new Text(_userData.userAge.toString())
        ],
      ),
    );
  }
}

用戶資料修改界面,和上面一樣在 didChangeDependencies 方法里面拿到數(shù)據(jù),點(diǎn)擊保存按鈕的時(shí)候 InheritedWidgetDemo.of(context).setUser(_userName, userAge) 修改數(shù)據(jù),當(dāng)返回展示界面的時(shí)候,界面會(huì)拿到新數(shù)據(jù)重建。

class EditUserPageWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("修改數(shù)據(jù)"),
      ),
      body: new EditUserWidget(),
    );
  }
}

class EditUserWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _EditUserState();
}

class _EditUserState extends State<EditUserWidget> {
  InheritedWidgetData _userData;
  String _userName;
  String _userAge;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _userData = InheritedWidgetDemo.of(context);
    _userName = _userData.userName;
    if (_userData.userAge > 0) {
      _userAge = _userData.userAge.toString();
    } else {
      _userAge = "";
    }
  }

  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new Column(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          new TextField(
            ///文本內(nèi)容控制器
            controller: TextEditingController.fromValue(new TextEditingValue(
              text: _userName,
              ///光標(biāo)移動(dòng)到最后面
              selection: TextSelection.fromPosition(new TextPosition(
                  affinity: TextAffinity.downstream, offset: _userName.length)),
            )),

            decoration: new InputDecoration(labelText: "輸入姓名"),

            ///內(nèi)容變化監(jiān)聽
            onChanged: (value) {
              _userName = value;
            },
          ),
          new TextField(
            ///文本內(nèi)容控制器
            controller: TextEditingController.fromValue(new TextEditingValue(
              text: _userAge,
              ///光標(biāo)移動(dòng)到最后面
              selection: TextSelection.fromPosition(new TextPosition(
                  affinity: TextAffinity.downstream, offset: _userAge.length)),
            )),

            decoration: new InputDecoration(labelText: "輸入年齡"),

            ///內(nèi)容變化監(jiān)聽
            onChanged: (value) {
              _userAge = value;
            },
          ),
          new FlatButton(
              onPressed: () {
                int userAge;
                try {
                  ///保存當(dāng)前修改的值
                  userAge = int.parse(_userAge);
                  InheritedWidgetDemo.of(context).setUser(_userName, userAge);
                  ///關(guān)閉當(dāng)前界面
                  Navigator.pop(context);
                } catch (e) {}
              },
              child: new Text("保存"))
        ],
      ),
    );
  }
}

由于用戶數(shù)據(jù)需要在全局共享,所以 InheritedWidgetDemo 要在頂層入口MaterialApp之上,當(dāng)然在日常開發(fā)并不是所有的數(shù)據(jù)都是全局保存的,每個(gè)子頁(yè)面都會(huì)管理自己所屬的數(shù)據(jù),只需要把 InheritedWidget 放在子頁(yè)面的最外層。

class AppPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new InheritedWidgetDemo(
        data: new InheritedWidgetData(),
        child: new MaterialApp(
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: new Scaffold(
            appBar: new AppBar(
              title: new Text("數(shù)據(jù)傳遞"),
            ),
            floatingActionButton: new Builder(builder: (context) {
              return new FloatingActionButton(
                  child: new Icon(Icons.edit),
                  onPressed: () {
                    ///push到編輯頁(yè)面
                    Navigator.of(context).push(
                        new MaterialPageRoute(builder: (BuildContext context) {
                      return EditUserPageWidget();
                    }));
                  });
            }),
            body: new CenterWidget(),
          ),
        ));
  }
}

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
  ///使用
    return AppPage();
  }
}
  • 關(guān)于 didChangeDependencies 的回調(diào),在生命周期提到過(guò),解釋是在 State 對(duì)象的依賴發(fā)生變化時(shí)會(huì)被調(diào)用,結(jié)合 InheritedWidget 看下面這個(gè)demo。

    Jun-15-2019 14-44-43

    兩個(gè)Text,一個(gè)依賴了 InheritedWidget,一個(gè)沒(méi)有。點(diǎn)擊按鈕修改 InheritedWidget 的值,上面的text會(huì)根據(jù)值的變化刷新重建,并回調(diào)了 didChangeDependencies ,下面的text由于沒(méi)有數(shù)據(jù)依賴,所以只有初始化的時(shí)候回調(diào)了一次 didChangeDependencies

    class InheritedRely extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return new _InheritedRelyState();
      }
    }
    
    class _InheritedRelyState extends State<InheritedRely> {
      int _state = 0;
    
      @override
      Widget build(BuildContext context) {
        return new InheritedTestWidget(
            data: _state,
            child: new MaterialApp(
              title: "Inherited數(shù)據(jù)依賴",
              home: new Scaffold(
                body: new Center(
                  child: new Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      new TextWidget(),
                      new Text1Widget()
                    ],
                  ),
                ),
                floatingActionButton: new FloatingActionButton(
                  onPressed: () {
                    setState(() {
                      ///修改state
                      _state++;
                    });
                  },
                  child: new Icon(Icons.add),
                ),
              ),
            ));
      }
    }
    
    class Text1Widget extends StatefulWidget {
    
      @override
      State<StatefulWidget> createState() {
        return new _Text1WidgetState();
      }
    }
    
    ///這個(gè)text沒(méi)有使用InheritedWidget的數(shù)據(jù)
    class _Text1WidgetState extends State<Text1Widget> {
      @override
      Widget build(BuildContext context) {
        return Text("這個(gè)text沒(méi)有使用InheritedWidget的數(shù)據(jù)");
      }
    
      @override
      void didChangeDependencies() {
        super.didChangeDependencies();
        print("_Text1------>>>>>>didChangeDependencies");
      }
    }
    
    
    
    ///這個(gè)text使用了InheritedWidget的數(shù)據(jù)
    class TextWidget extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return _TextWidgetState();
      }
    }
    
    class _TextWidgetState extends State<TextWidget> {
      @override
      Widget build(BuildContext context) {
        ///InheritedTestWidget.of(context) 依賴了InheritedWidget的數(shù)據(jù)
        return Text("這個(gè)text使用了InheritedWidget的數(shù)據(jù)" +
            InheritedTestWidget.of(context).toString());
      }
    
      @override
      void didChangeDependencies() {
        super.didChangeDependencies();
        print("_Text------>>>>>>didChangeDependencies");
      }
    }
    
    class InheritedTestWidget extends InheritedWidget {
      final int data;
    
      InheritedTestWidget({@required this.data, @required Widget child})
          : super(child: child);
    
      @override
      bool updateShouldNotify(InheritedTestWidget oldWidget) {
        return data != oldWidget.data;
      }
    
      static int of(BuildContext context) {
        final InheritedTestWidget user =
            context.inheritFromWidgetOfExactType(InheritedTestWidget);
        return user.data;
      }
    }
    
    

    代碼和演示清楚的解釋了,當(dāng) InheritedWidgetState 對(duì)象發(fā)生變化時(shí),它下面子組件只要是對(duì) InheritedWidget 有依賴的都會(huì)調(diào) didChangeDependenciesbuild 進(jìn)行刷新重建。

  • scoped_model

    上面的例子展示了如何使用 InheritedWidget ,有個(gè)問(wèn)題就是在數(shù)據(jù)變化之后每次都需要手動(dòng)調(diào)動(dòng) setState 方法才會(huì)進(jìn)行重建。如何讓組件自動(dòng)刷新不需要我們自己手動(dòng)調(diào)用 setState 方法呢。

    這需要使用到 scoped_model 庫(kù) , scoped_model 是基于 InheritedWidget 實(shí)現(xiàn)的,源碼稍后分析,先通過(guò)剛剛用戶資料編輯的demo來(lái)學(xué)習(xí)如何使用這個(gè)庫(kù),展示效果和上面的demo一樣。

    因?yàn)槭堑谌綆?kù)第一步肯定是添加依賴 scoped_model: ^1.0.1 。文檔在這里(需要梯子)。

    用戶model,繼承 Model 提供一個(gè) of 方法供組件調(diào)用獲取model,注意 rebuildOnChange參數(shù)是可選的,默認(rèn)為fales,為false的時(shí)候獲取的model數(shù)據(jù)變化之后不會(huì)刷新界面。

    class UserMode extends Model {
      String userName;
      int userAge;
    
      UserMode({this.userName, this.userAge});
    
      void setUserInfo(String userName, int userAge) {
        this.userName = userName;
        this.userAge = userAge;
        ///修改完數(shù)據(jù) 調(diào)用刷新方法
        notifyListeners();
      }
    
      ///rebuildOnChange 此方法拿到的model對(duì)象修改后是否需要刷新
      static UserMode of(BuildContext context) =>
          ScopedModel.of<UserMode>(context, rebuildOnChange: true);
    
    }
    

    展示組件,邏輯基本和 InheritedWidget 的一樣,初始化的時(shí)候模擬請(qǐng)求,延遲3秒修改數(shù)據(jù),當(dāng)沒(méi)有數(shù)據(jù)的時(shí)候加載等待小圓圈,不同的是獲取數(shù)據(jù)的方法,這里變成通過(guò)model的 of 方法。

    class CenterWidget extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => _CenterWidgetState();
    }
    
    class _CenterWidgetState extends State<CenterWidget> {
      @override
      void initState() {
        super.initState();
        _getUserData();
      }
    
      _getUserData() async {
        ///模擬網(wǎng)絡(luò)請(qǐng)求 等待五秒
        await Future.delayed(Duration(seconds: 3));
        UserMode.of(context).setUserInfo("李華", 22);
      }
    
      @override
      Widget build(BuildContext context) {
        return new Center(
            /// 數(shù)據(jù)為空顯示加載圓圈
            child: UserMode.of(context).userName == null
                ? CircularProgressIndicator()
                : new UserInfoWidget());
      }
    }
    

    除了 ScopedModel.of 方法還可以通過(guò) ScopedModelDescendant 來(lái)獲取,在需要獲取數(shù)據(jù)的組件外加一層ScopedModelDescendant ,用戶信息使用此方法。

    
    ///用戶信息Widget
    class UserInfoWidget extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => _UserInfoState();
    }
    
    class _UserInfoState extends State<UserInfoWidget> {
      @override
      Widget build(BuildContext context) {
        return new ScopedModelDescendant<UserMode>(builder: (context, child, model) {
          return new Center(
            child: new Column(
              mainAxisAlignment: MainAxisAlignment.center,
              mainAxisSize: MainAxisSize.max,
              children: <Widget>[
                ///可以直接通過(guò)mode拿到數(shù)據(jù)
                new Text(model.userName),
                new Text(model.userAge.toString())
              ],
            ),
          );
        });
      }
    }
    

    信息編輯頁(yè)面邏輯也一樣,獲取和修改數(shù)據(jù)的方式不一樣。

    class EditUserPageWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          appBar: new AppBar(
            title: new Text("修改數(shù)據(jù)"),
          ),
          body: new EditUserWidget(),
        );
      }
    }
    
    class EditUserWidget extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => _EditUserState();
    }
    
    class _EditUserState extends State<EditUserWidget> {
      UserMode _userMode;
    
      String _userName;
      String _userAge;
    
      @override
      Widget build(BuildContext context) {
        _userMode = UserMode.of(context);
        _userName = _userMode.userName;
        _userAge = _userMode.userAge.toString();
    
        return new Center(
          child: new Column(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              new TextField(
                ///文本內(nèi)容控制器
                controller: TextEditingController.fromValue(new TextEditingValue(
                  text: _userName,
                  ///光標(biāo)移動(dòng)到最后面
                  selection: TextSelection.fromPosition(new TextPosition(
                      affinity: TextAffinity.downstream, offset: _userName.length)),
                )),
    
                decoration: new InputDecoration(labelText: "輸入姓名"),
    
                ///內(nèi)容變化監(jiān)聽
                onChanged: (value) {
                  _userName = value;
                },
              ),
              new TextField(
                ///文本內(nèi)容控制器
                controller: TextEditingController.fromValue(new TextEditingValue(
                  text: _userAge,
                  selection: TextSelection.fromPosition(new TextPosition(
                      affinity: TextAffinity.downstream, offset: _userAge.length)),
                )),
    
                decoration: new InputDecoration(labelText: "輸入年齡"),
    
                ///內(nèi)容變化監(jiān)聽
                onChanged: (value) {
                  _userAge = value;
                },
              ),
              new FlatButton(
                  onPressed: () {
                    int userAge;
                    try {
                      ///保存當(dāng)前修改的值
                      userAge = int.parse(_userAge);
                      _userMode.setUserInfo(_userName, userAge);
    
                      ///關(guān)閉當(dāng)前界面
                      Navigator.pop(context);
                    } catch (e) {}
                  },
                  child: new Text("保存"))
            ],
          ),
        );
      }
    }
    
    

    主Widget,和 InheritedWidget 一樣需要在最外層,使用 ScopedModel

    class ScopedModelDemo extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return new _ScopedModelDemoState();
      }
    }
    
    class _ScopedModelDemoState extends State<ScopedModelDemo> {
    
      @override
      Widget build(BuildContext context) {
        return new ScopedModel<UserMode>(
            model: UserMode(),
            child: new MaterialApp(
              theme: ThemeData(
                primarySwatch: Colors.blue,
              ),
              home: new Scaffold(
                appBar: new AppBar(
                  title: new Text("ScopedModelDemo"),
                ),
                floatingActionButton: new Builder(builder: (context) {
                  return new FloatingActionButton(
                      child: new Icon(Icons.edit),
                      onPressed: () {
                        ///push到編輯頁(yè)面
                        Navigator.of(context).push(
                            new MaterialPageRoute(builder: (BuildContext context) {
                          return EditUserPageWidget();
                        }));
                      });
                }),
                body: new CenterWidget(),
              ),
            ));
      }
    }
    

    效果和上面一樣,不上圖了。代碼中沒(méi)有任何地方使用到 setState 數(shù)據(jù)更新之后,界面自動(dòng)刷新重建。上面說(shuō)到了這個(gè)庫(kù)也是基于 InheritedWidget ,具體如何實(shí)現(xiàn)的,通過(guò)源碼來(lái)分析。

    首先看下Model的源碼,

    abstract class Model extends Listenable {
      final Set<VoidCallback> _listeners = Set<VoidCallback>();
      int _version = 0;
      int _microtaskVersion = 0;
    
      /// [listener] will be invoked when the model changes.
      @override
      void addListener(VoidCallback listener) {
        _listeners.add(listener);
      }
    
      /// [listener] will no longer be invoked when the model changes.
      @override
      void removeListener(VoidCallback listener) {
        _listeners.remove(listener);
      }
    
      /// Returns the number of listeners listening to this model.
      int get listenerCount => _listeners.length;
    
      /// Should be called only by [Model] when the model has changed.
      @protected
      void notifyListeners() {
        // We schedule a microtask to debounce multiple changes that can occur
        // all at once.
        if (_microtaskVersion == _version) {
          _microtaskVersion++;
          scheduleMicrotask(() {
            _version++;
            _microtaskVersion = _version;
    
            // Convert the Set to a List before executing each listener. This
            // prevents errors that can arise if a listener removes itself during
            // invocation!
            _listeners.toList().forEach((VoidCallback listener) => listener());
          });
        }
      }
    }
    

    Model繼承至Listenable,維護(hù)著一個(gè)VoidCallback類型的集合,

    /// Signature of callbacks that have no arguments and return no data.
    typedef VoidCallback = void Function();
    

    VoidCallback 就是一個(gè)沒(méi)有返回值的方法,notifyListeners 方法里面遍歷調(diào)用了所有集合里面的方法。

    再看入口 ScopedModel,

    class ScopedModel<T extends Model> extends StatelessWidget {
      /// The [Model] to provide to [child] and its descendants.
      final T model;
    
      /// The [Widget] the [model] will be available to.
      final Widget child;
    
      ScopedModel({@required this.model, @required this.child})
          : assert(model != null),
            assert(child != null);
    
      @override
      Widget build(BuildContext context) {
        return AnimatedBuilder(
          animation: model,
          builder: (context, _) => _InheritedModel<T>(model: model, child: child),
        );
      }
    
      static T of<T extends Model>(
        BuildContext context, {
        bool rebuildOnChange = false,
      }) {
        final Type type = _type<_InheritedModel<T>>();
    
        Widget widget = rebuildOnChange
            ? context.inheritFromWidgetOfExactType(type)
            : context.ancestorWidgetOfExactType(type);
    
        if (widget == null) {
          throw new ScopedModelError();
        } else {
          return (widget as _InheritedModel<T>).model;
        }
      }
      
    }
    

    代碼很簡(jiǎn)單of 方法為Model方法提供獲取值的方法,而且是通過(guò) inheritFromWidgetOfExactType 和上面 InheritedWidgetof差不多,這里也可以解釋了上面Model里面為什么rebuildOnChange 為fals的時(shí)候不會(huì)更新界面的原因。

    然后查看 bulid方法返回的是一個(gè) AnimatedBuilder ,兩個(gè)參數(shù),model和 _InheritedModel,查看 _InheritedModel,果然,繼承了 InheritedWidget。并且存放了model和一個(gè)int類型的 version通過(guò)version來(lái)判斷是否更新。

    class _InheritedModel<T extends Model> extends InheritedWidget {
      final T model;
      final int version;
    
      _InheritedModel({Key key, Widget child, T model})
          : this.model = model,
            this.version = model._version,
            super(key: key, child: child);
    
      @override
      bool updateShouldNotify(_InheritedModel<T> oldWidget) =>
          (oldWidget.version != version);
    }
    

    回到 AnimatedBuilder 查看它的代碼

    class AnimatedBuilder extends AnimatedWidget {
      /// Creates an animated builder.
      ///
      /// The [animation] and [builder] arguments must not be null.
      const AnimatedBuilder({
        Key key,
        @required Listenable animation,
        @required this.builder,
        this.child,
      }) : assert(animation != null),
           assert(builder != null),
           super(key: key, listenable: animation);
    
      /// Called every time the animation changes value.
      final TransitionBuilder builder;
    
      final Widget child;
    
      @override
      Widget build(BuildContext context) {
        return builder(context, child);
      }
    }
    

    看不出有什么重要的代碼,點(diǎn)擊super往上走看AnimatedWidget的代碼,

    abstract class AnimatedWidget extends StatefulWidget {
     ///...
    }
    
    class _AnimatedState extends State<AnimatedWidget> {
      @override
      void initState() {
        super.initState();
        widget.listenable.addListener(_handleChange);
      }
    
      @override
      void didUpdateWidget(AnimatedWidget oldWidget) {
        super.didUpdateWidget(oldWidget);
        if (widget.listenable != oldWidget.listenable) {
          oldWidget.listenable.removeListener(_handleChange);
          widget.listenable.addListener(_handleChange);
        }
      }
    
      @override
      void dispose() {
        widget.listenable.removeListener(_handleChange);
        super.dispose();
      }
    
      void _handleChange() {
        setState(() {
          // The listenable's state is our build state, and it changed already.
        });
      }
    
      @override
      Widget build(BuildContext context) => widget.build(context);
    }
    

    看到這里就很清晰了,通過(guò)觀察者模式,_InheritedModel 里的數(shù)據(jù)也就是Model是被觀察者,在 _AnimatedStateinitStatedispose方法來(lái) 訂閱和取消,Model發(fā)生變化時(shí),去調(diào)用notifyListeners 來(lái)通知所有觀察者執(zhí)行 setState 刷新重構(gòu)造界面。

    還有一個(gè)ScopedModelDescendant ,

    class ScopedModelDescendant<T extends Model> extends StatelessWidget {
      /// Called whenever the [Model] changes.
      final ScopedModelDescendantBuilder<T> builder;
    
      /// An optional constant child that does not depend on the model.  This will
      /// be passed as the child of [builder].
      final Widget child;
    
      /// An optional constant that determines whether the
      final bool rebuildOnChange;
    
      /// Constructor.
      ScopedModelDescendant({
        @required this.builder,
        this.child,
        this.rebuildOnChange = true,
      });
    
      @override
      Widget build(BuildContext context) {
        return builder(
          context,
          child,
          ScopedModel.of<T>(context, rebuildOnChange: rebuildOnChange),
        );
      }
    }
    

本質(zhì)也是ScopedModel.of 方法拿到數(shù)據(jù)的。

初學(xué)小白的個(gè)人學(xué)習(xí)筆記,歡迎大佬檢查,如有不對(duì)請(qǐng)指出。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容