美文网首页
[Flutter开发]06.使用InheritedWidget实

[Flutter开发]06.使用InheritedWidget实

作者: 沈枫_ShenF | 来源:发表于2020-03-26 21:54 被阅读0次

接上一篇文章,全局管理状态的provider包可以简单通过InheritedWidget来实现,不过在此之前,需要先认识一下InheritedWidget。

一. InheritedWidget

InheritedWidget有个很重要的特性,它提供了一种方式,使得数据可以在widget树中从上到下传递、共享,比如在应用的根widget中通过InheritedWidget共享了一个数据,那么我们便可以在任意子widget中来获取该共享的数据!

在之前介绍State的生命周期时,State对象有一个didChangeDependencies回调,它会在“依赖”发生变化时被Flutter Framework调用。而这个“依赖”指的就是子widget是否使用了父widget中InheritedWidget的数据!如果使用了,则代表子widget依赖有依赖InheritedWidget;如果没有使用则代表没有依赖。这种机制可以使子组件在所依赖的InheritedWidget变化时来更新自身!

接下来,举个例子来说明一下。

  1. 先创建个继承InheritedWidget的类DataWidget:
class DataWidget extends InheritedWidget {
  DataWidget({
    @required this.data,
    Widget child
  }) :super(child: child);

  final int data; 

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

  //该回调决定当data发生变化时,是否通知子树中依赖data的Widget  
  @override
  bool updateShouldNotify(DataWidget old) {
    //true: 子树中依赖本widget,从而子widget的`state.didChangeDependencies`会被调用
    return old.data != data;
  }
}
  1. 然后实现一个组件_TestWidget,在其build方法中使用DataWidget中的数据。
class _TestWidget extends StatefulWidget {
  @override
  _TestWidgetState createState() => new _TestWidgetState();
}

class _TestWidgetState extends State<_TestWidget> {
  @override
  Widget build(BuildContext context) {
    //使用InheritedWidget中的共享数据
    return Text(DataWidget
        .of(context)
        .data
        .toString());
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    //父widget中的InheritedWidget改变(updateShouldNotify返回true)时会被调用。
    //如果build中没有依赖InheritedWidget,则此回调不会被调用。
    print("Dependencies change");
  }
}
  1. 再在另一个组件中使用DataWidget,并使_TestWidget成为DataWidget的子组件。
class TestRoute extends StatefulWidget {
  @override
  _TestRouteState createState() => new _TestRouteState();
}

class _TestRouteState extends State<TestRoute> {
  int count = 0;

  @override
  Widget build(BuildContext context) {
    return  Center(
      child: DataWidget( 
        data: count,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.only(bottom: 20.0),
              child: _TestWidget(),//子widget中依赖DataWidget
            ),
            RaisedButton(
              child: Text("Increment"),
              //每次点击,count自增,然后重新build, DataWidget的data将被更新  
              onPressed: () => setState(() => ++count),
            )
          ],
        ),
      ),
    );
  }
}

上面例子就产生了依赖,子组件_TestWidget 的didChangeDependencies()会被调用。如果_TestWidget的build方法中没有使用ShareDataWidget的数据,那它就没有依赖ShareDataWidget,它的didChangeDependencies()也将不会被调用。

如果不想在DataWidget发生变化时调用__TestWidgetState的didChangeDependencies()方法,我们可以把inheritFromWidgetOfExactType()方法换成ancestorInheritedElementForWidgetOfExactType():

static DataWidget of(BuildContext context) {
  //return context.inheritFromWidgetOfExactType(ShareDataWidget);
  return context.ancestorInheritedElementForWidgetOfExactType(ShareDataWidget).widget;
}

这两个方法有什么区别呢?看源码:

@override
InheritedElement ancestorInheritedElementForWidgetOfExactType(Type targetType) {
  final InheritedElement ancestor = _inheritedWidgets == null ? null :  _inheritedWidgets[targetType];
  return ancestor;
}

@override
InheritedWidget inheritFromWidgetOfExactType(Type targetType, { Object aspect }) {
  final InheritedElement ancestor = _inheritedWidgets == null ? null :   _inheritedWidgets[targetType];
  //多出的部分
  if (ancestor != null) {
    assert(ancestor is InheritedElement);
    return inheritFromElement(ancestor, aspect: aspect);
  }
  _hadUnsatisfiedDependencies = true;
  return null;
}

可以看出两者的区别是:inheritFromWidgetOfExactType() 多调了inheritFromElement方法,该方法实现如下:

@override
InheritedWidget inheritFromElement(InheritedElement ancestor, { Object aspect }) {
  //注册依赖关系
  _dependencies ??= HashSet<InheritedElement>();
  _dependencies.add(ancestor);
  ancestor.updateDependencies(this, aspect);
  return ancestor.widget;
}

从该方法实现中,可以看出,ancestor被加到依赖数组_dependencies中,从而注册了依赖关系,也就是说使用ancestorInheritedElementForWidgetOfExactType方法不会有依赖,自然就不会调用__TestWidgetState的didChangeDependencies()方法了。

二. 使用InheritedWidget实现Provider

上一篇文章中说到,可以使用Provider来实现全局状态管理,它 是基于InheritedWidget来实现状态共享的。那接下来简单使用InheritedWidget实现一个Provider。

相关文章

网友评论

      本文标题:[Flutter开发]06.使用InheritedWidget实

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