zoukankan      html  css  js  c++  java
  • 02-08 flutter InheritedWidget

    InheritedWidget提供了一种数据在widget树中从上到下传递、共享的方式 ,

    简而言之

    InheritedWidget 中暴露出来的数据能有效地向下(子widget)传播(和共享)信息

    如Flutter SDK中正是通过InheritedWidget来共享应用主题(Theme)和Locale (当前语言环境)信息的。

    InheritedWidget

    abstract class InheritedWidget extends ProxyWidget
    

    为了使用 先定义一个子类InheritedProvider

    class InheritedProvider<T> extends InheritedWidget{
    
      final T data;//需要在子树中共享的数据
    
      InheritedProvider({
        this.data,
        Widget child,
      }) :super(child: child);
    
      //定义一个便捷方法,方便子树中的widget获取共享数据  
      static InheritedProvider of<T>(BuildContext context){
        return context.inheritFromWidgetOfExactType(InheritedProvider);
      }
     //该回调决定当data发生变化时,是否通知子树中依赖data的Widget  
      @override
      bool updateShouldNotify(InheritedProvider<T> oldWidget) {
         //如果返回true,则子树中依赖(build函数中有调用)本widget
        //的子widget的`state.didChangeDependencies`会被调用
        return oldWidget.data != data;
      }
    
    }
    

    InheritedProvider类的目的是为它的所有子widget提供数据

    InheritedWidget在widget树中数据传递方向是从上到下的,并且可以跨级传递

    访问inhertedProvider中的数据

    final InheritedProvider inheritedWidget  = InheritedProvider.of(context);
    
    return new Container(
             color: inheritedWidget.data.color,
    );
    

    didChangeDependencies

    State对象有一个didChangeDependencies回调,它会在“依赖”发生变化时被Flutter Framework调用。而这个“依赖”指的就是子widget是否使用了父widget中InheritedWidget的数据!如果使用了,则代表子widget依赖有依赖InheritedWidget;如果没有使用则代表没有依赖。这种机制可以使子组件在所依赖的InheritedWidget变化时来更新自身!比如当主题、locale(语言)等发生变化时,依赖其的子widget的didChangeDependencies方法将会被调用。

    如果我们只想在子widget中引用InheritedProvider数据,但却不希望在InheritedProvider发生变化时调用子Widget的didChangeDependencies()方法应该怎么办?其实答案很简单,我们只需要将InheritedProvider.of()的实现改一下即可:

    //定义一个便捷方法,方便子树中的widget获取共享数据
    static InheritedProvider of(BuildContext context) {
      //return context.dependOnInheritedWidgetOfExactType<ShareDataWidget>();
      return context.getElementForInheritedWidgetOfExactType<ShareDataWidget>().widget;
    }
    
    @override
    InheritedElement getElementForInheritedWidgetOfExactType<T extends InheritedWidget>() {
      assert(_debugCheckStateIsActiveForAncestorLookup());
      final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[T];
      return ancestor;
    }
    @override
    InheritedWidget dependOnInheritedWidgetOfExactType({ Object aspect }) {
      assert(_debugCheckStateIsActiveForAncestorLookup());
      final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[T];
      //多出的部分
      if (ancestor != null) {
        assert(ancestor is InheritedElement);
        return dependOnInheritedElement(ancestor, aspect: aspect) as T;
      }
      _hadUnsatisfiedDependencies = true;
      return null;
    }
    

    我们可以看到,dependOnInheritedWidgetOfExactType()getElementForInheritedWidgetOfExactType()多调了dependOnInheritedElement方法,dependOnInheritedElement源码如下:

      @override
      InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect }) {
        assert(ancestor != null);
        _dependencies ??= HashSet<InheritedElement>();
        _dependencies.add(ancestor);
        ancestor.updateDependencies(this, aspect);
        return ancestor.widget;
      }
    

    调用dependOnInheritedWidgetOfExactType()getElementForInheritedWidgetOfExactType()的区别就是前者会注册依赖关系,而后者不会,所以在调用dependOnInheritedWidgetOfExactType()时,InheritedWidget和依赖它的子孙组件关系便完成了注册,之后当InheritedWidget发生变化时,就会更新依赖它的子孙组件,也就是会调这些子孙组件的didChangeDependencies()方法和build()方法。而当调用的是 getElementForInheritedWidgetOfExactType()时,由于没有注册依赖关系,所以之后当InheritedWidget发生变化时,就不会更新相应的子孙Widget。

    点击"Increment"按钮后,会调用界面state的setState()方法,此时会重新构建整个页面,由于示例中, 并没有任何缓存,所以它也都会被重新构建,所以也会调用build()方法。

  • 相关阅读:
    传统IO总结
    关于JAVA垃圾回收的一些小tips
    一个爬喜马拉雅音频的例子
    return研究
    Java基础知识-java.util.concurrent包下常见类的使用
    <a>链接的四个伪类顺序
    前端面试题
    setTimeout的作用以及setTimeout延时0毫秒的作用
    闭包的使用
    JavaScript typeof obj === ‘object’ 这样写有什么问题
  • 原文地址:https://www.cnblogs.com/xiaowuqing/p/14028014.html
Copyright © 2011-2022 走看看