美文网首页
数据传递/状态管理 一InheritedWidget

数据传递/状态管理 一InheritedWidget

作者: 烫烫琨烫烫烫烫琨烫烫 | 来源:发表于2019-06-24 12:37 被阅读0次

    数据传递/状态管理 一InheritedWidget

    InheritedWidget是一个特殊的widget,可以存储和获取数据,子组件可以获取到存储的数据,常用的 MediaQueryTheme 就是继承了 InheritedWidget。先通过MediaQuery来学习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 }) {
        ///...
      }
    }
    

    通过 MediaQuery.of(context) 获取到MediaQueryData对象,然后获取到设备屏幕相关的信息。

    ///获取屏幕宽度
    MediaQuery.of(context).size.width;
    

    代码查找,下面这些地方创建了MediaQuery

    WX20190615-113309@2x

    在app.dart里面可以发现 WidgetsApp 如下代码,build 方法返回一个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,
          ),
        ),
      );
    }
    

    继续通过代码查找在 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,
      );
    }
    

    通过这些代码,可以推断出 MaterialApphome是属于MediaQuery的子组件,所有home下面所有组件都能够通过 MediaQuery.of(context) 来获取其共享的数据。但是注意并不是任何组件的任何地方,只有当前组件执行完 didChangeDependencies 方法之后才能正确的获取到 InheritedWidget 对象的数据。

    • 示例

      完成下面的示例,页面进来加载用户信息,保存和展示,然后在另外的页面修改编辑后返回,展示的数据也改变了:

    Jun-15-2019 13-16-35

    完成上面的示例首先创建一个数据实体类,

    ///共享的数据
    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 存放着用户的数据。提供一个of的静态方法供子组件调用,复写updateShouldNotify 方法判断是否需要更新。

    ///主Widget 继承InheritedWidget 存放数据
    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;
      }
    }
    

    数据展示Widget,在 didChangeDependencies 方法里面获取用户数据。页面初始化开启模拟网络请求等待3秒后,调用 setUser 方法修改 InheritedWidgetDemo 中的数据,然后重建界面。当用户信息为空的话页面显示加载等待组件。

    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 {
        ///模拟网络请求 等待五秒
        await Future.delayed(Duration(seconds: 3));
        InheritedWidgetDemo.of(context).setUser("李华", 18);
        ///setState 触发页面刷新
        setState(() {});
      }
    
      @override
      Widget build(BuildContext context) {
        return new Center(
          /// 数据为空显示加载圆圈
          child: _userData.userName == ""
              ? CircularProgressIndicator()
              : new UserInfoWidget(),
        );
      }
    }
    

    用户信息展示Widget,和上面的Widget一样,在 didChangeDependencies 方法里面获取用户数据并且展示。

    ///用户信息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 方法里面拿到数据,点击保存按钮的时候 InheritedWidgetDemo.of(context).setUser(_userName, userAge) 修改数据,当返回展示界面的时候,界面会拿到新数据重建。

    class EditUserPageWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          appBar: new AppBar(
            title: new Text("修改数据"),
          ),
          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(
                ///文本内容控制器
                controller: TextEditingController.fromValue(new TextEditingValue(
                  text: _userName,
                  ///光标移动到最后面
                  selection: TextSelection.fromPosition(new TextPosition(
                      affinity: TextAffinity.downstream, offset: _userName.length)),
                )),
    
                decoration: new InputDecoration(labelText: "输入姓名"),
    
                ///内容变化监听
                onChanged: (value) {
                  _userName = value;
                },
              ),
              new TextField(
                ///文本内容控制器
                controller: TextEditingController.fromValue(new TextEditingValue(
                  text: _userAge,
                  ///光标移动到最后面
                  selection: TextSelection.fromPosition(new TextPosition(
                      affinity: TextAffinity.downstream, offset: _userAge.length)),
                )),
    
                decoration: new InputDecoration(labelText: "输入年龄"),
    
                ///内容变化监听
                onChanged: (value) {
                  _userAge = value;
                },
              ),
              new FlatButton(
                  onPressed: () {
                    int userAge;
                    try {
                      ///保存当前修改的值
                      userAge = int.parse(_userAge);
                      InheritedWidgetDemo.of(context).setUser(_userName, userAge);
                      ///关闭当前界面
                      Navigator.pop(context);
                    } catch (e) {}
                  },
                  child: new Text("保存"))
            ],
          ),
        );
      }
    }
    

    由于用户数据需要在全局共享,所以 InheritedWidgetDemo 要在顶层入口MaterialApp之上,当然在日常开发并不是所有的数据都是全局保存的,每个子页面都会管理自己所属的数据,只需要把 InheritedWidget 放在子页面的最外层。

    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("数据传递"),
                ),
                floatingActionButton: new Builder(builder: (context) {
                  return new FloatingActionButton(
                      child: new Icon(Icons.edit),
                      onPressed: () {
                        ///push到编辑页面
                        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();
      }
    }
    
    • 关于 didChangeDependencies 的回调,在生命周期提到过,解释是在 State 对象的依赖发生变化时会被调用,结合 InheritedWidget 看下面这个demo。

      Jun-15-2019 14-44-43

      两个Text,一个依赖了 InheritedWidget,一个没有。点击按钮修改 InheritedWidget 的值,上面的text会根据值的变化刷新重建,并回调了 didChangeDependencies ,下面的text由于没有数据依赖,所以只有初始化的时候回调了一次 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数据依赖",
                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();
        }
      }
      
      ///这个text没有使用InheritedWidget的数据
      class _Text1WidgetState extends State<Text1Widget> {
        @override
        Widget build(BuildContext context) {
          return Text("这个text没有使用InheritedWidget的数据");
        }
      
        @override
        void didChangeDependencies() {
          super.didChangeDependencies();
          print("_Text1------>>>>>>didChangeDependencies");
        }
      }
      
      
      
      ///这个text使用了InheritedWidget的数据
      class TextWidget extends StatefulWidget {
        @override
        State<StatefulWidget> createState() {
          return _TextWidgetState();
        }
      }
      
      class _TextWidgetState extends State<TextWidget> {
        @override
        Widget build(BuildContext context) {
          ///InheritedTestWidget.of(context) 依赖了InheritedWidget的数据
          return Text("这个text使用了InheritedWidget的数据" +
              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;
        }
      }
      
      

      代码和演示清楚的解释了,当 InheritedWidgetState 对象发生变化时,它下面子组件只要是对 InheritedWidget 有依赖的都会调 didChangeDependenciesbuild 进行刷新重建。

    • scoped_model

      上面的例子展示了如何使用 InheritedWidget ,有个问题就是在数据变化之后每次都需要手动调动 setState 方法才会进行重建。如何让组件自动刷新不需要我们自己手动调用 setState 方法呢。

      这需要使用到 scoped_model 库 , scoped_model 是基于 InheritedWidget 实现的,源码稍后分析,先通过刚刚用户资料编辑的demo来学习如何使用这个库,展示效果和上面的demo一样。

      因为是第三方库第一步肯定是添加依赖 scoped_model: ^1.0.1文档在这里(需要梯子)。

      用户model,继承 Model 提供一个 of 方法供组件调用获取model,注意 rebuildOnChange参数是可选的,默认为fales,为false的时候获取的model数据变化之后不会刷新界面

      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;
          ///修改完数据 调用刷新方法
          notifyListeners();
        }
      
        ///rebuildOnChange 此方法拿到的model对象修改后是否需要刷新
        static UserMode of(BuildContext context) =>
            ScopedModel.of<UserMode>(context, rebuildOnChange: true);
      
      }
      

      展示组件,逻辑基本和 InheritedWidget 的一样,初始化的时候模拟请求,延迟3秒修改数据,当没有数据的时候加载等待小圆圈,不同的是获取数据的方法,这里变成通过model的 of 方法。

      class CenterWidget extends StatefulWidget {
        @override
        State<StatefulWidget> createState() => _CenterWidgetState();
      }
      
      class _CenterWidgetState extends State<CenterWidget> {
        @override
        void initState() {
          super.initState();
          _getUserData();
        }
      
        _getUserData() async {
          ///模拟网络请求 等待五秒
          await Future.delayed(Duration(seconds: 3));
          UserMode.of(context).setUserInfo("李华", 22);
        }
      
        @override
        Widget build(BuildContext context) {
          return new Center(
              /// 数据为空显示加载圆圈
              child: UserMode.of(context).userName == null
                  ? CircularProgressIndicator()
                  : new UserInfoWidget());
        }
      }
      

      除了 ScopedModel.of 方法还可以通过 ScopedModelDescendant 来获取,在需要获取数据的组件外加一层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>[
                  ///可以直接通过mode拿到数据
                  new Text(model.userName),
                  new Text(model.userAge.toString())
                ],
              ),
            );
          });
        }
      }
      

      信息编辑页面逻辑也一样,获取和修改数据的方式不一样。

      class EditUserPageWidget extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
          return new Scaffold(
            appBar: new AppBar(
              title: new Text("修改数据"),
            ),
            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(
                  ///文本内容控制器
                  controller: TextEditingController.fromValue(new TextEditingValue(
                    text: _userName,
                    ///光标移动到最后面
                    selection: TextSelection.fromPosition(new TextPosition(
                        affinity: TextAffinity.downstream, offset: _userName.length)),
                  )),
      
                  decoration: new InputDecoration(labelText: "输入姓名"),
      
                  ///内容变化监听
                  onChanged: (value) {
                    _userName = value;
                  },
                ),
                new TextField(
                  ///文本内容控制器
                  controller: TextEditingController.fromValue(new TextEditingValue(
                    text: _userAge,
                    selection: TextSelection.fromPosition(new TextPosition(
                        affinity: TextAffinity.downstream, offset: _userAge.length)),
                  )),
      
                  decoration: new InputDecoration(labelText: "输入年龄"),
      
                  ///内容变化监听
                  onChanged: (value) {
                    _userAge = value;
                  },
                ),
                new FlatButton(
                    onPressed: () {
                      int userAge;
                      try {
                        ///保存当前修改的值
                        userAge = int.parse(_userAge);
                        _userMode.setUserInfo(_userName, userAge);
      
                        ///关闭当前界面
                        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到编辑页面
                          Navigator.of(context).push(
                              new MaterialPageRoute(builder: (BuildContext context) {
                            return EditUserPageWidget();
                          }));
                        });
                  }),
                  body: new CenterWidget(),
                ),
              ));
        }
      }
      

      效果和上面一样,不上图了。代码中没有任何地方使用到 setState 数据更新之后,界面自动刷新重建。上面说到了这个库也是基于 InheritedWidget ,具体如何实现的,通过源码来分析。

      首先看下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,维护着一个VoidCallback类型的集合,

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

      VoidCallback 就是一个没有返回值的方法,notifyListeners 方法里面遍历调用了所有集合里面的方法。

      再看入口 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;
          }
        }
        
      }
      

      代码很简单of 方法为Model方法提供获取值的方法,而且是通过 inheritFromWidgetOfExactType 和上面 InheritedWidgetof差不多,这里也可以解释了上面Model里面为什么rebuildOnChange 为fals的时候不会更新界面的原因。

      然后查看 bulid方法返回的是一个 AnimatedBuilder ,两个参数,model和 _InheritedModel,查看 _InheritedModel,果然,继承了 InheritedWidget。并且存放了model和一个int类型的 version通过version来判断是否更新。

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

      看不出有什么重要的代码,点击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);
      }
      

      看到这里就很清晰了,通过观察者模式,_InheritedModel 里的数据也就是Model是被观察者,在 _AnimatedStateinitStatedispose方法来 订阅和取消,Model发生变化时,去调用notifyListeners 来通知所有观察者执行 setState 刷新重构造界面。

      还有一个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),
          );
        }
      }
      

    本质也是ScopedModel.of 方法拿到数据的。

    初学小白的个人学习笔记,欢迎大佬检查,如有不对请指出。

    相关文章

      网友评论

          本文标题:数据传递/状态管理 一InheritedWidget

          本文链接:https://www.haomeiwen.com/subject/xuvnqctx.html