美文网首页
InheritedWidget使用说明

InheritedWidget使用说明

作者: oceanLong | 来源:发表于2020-02-13 01:39 被阅读0次

    InheritedWidget

    概述

    在Flutter进行界面开发时,我们经常会遇到数据传递的问题。由于Flutter采用节点树的方式组织页面,以致于一个普通页面的节点层级会很深。此时,我们如果还是一层层传递数据,当需要修改数据时,就会比较麻烦。

    此时,我们需要一种机制,能够让某一个节点下的所有子节点,访问该节点下的数据。

    InheritedWidget就满足了我们这一需求。

    使用方法

    我们创建一个继承InheritedWidget的Widget。

    class MyInheritedWidget extends InheritedWidget {
      final int data;
    
      MyInheritedWidget(@required this.data, Widget child) : super(child: child);
    
      static MyInheritedWidget getData(BuildContext context) {
        return context.inheritFromWidgetOfExactType(MyInheritedWidget);
      }
    
    
      @override
      bool updateShouldNotify(MyInheritedWidget oldWidget) {
        return oldWidget.data != data;
      }
    
    
    }
    

    可以看到,我们提供了三个方法。

    构造方法

    InheritedWidget本身是一个没有界面的Widget,或者说是一个代理Widget,我们需要传入我们实际的Widget。

    所以,在构造方法中,我们需要传入两个参数,一个是我们希望共享的数据(在本例中数据是int型,实际业务中共享的通常是一个相对复杂的数据),另一个就是我们带界面的Widget。

    数据获取方法

      static MyInheritedWidget getData(BuildContext context) {
        return context.inheritFromWidgetOfExactType(MyInheritedWidget);
      }
    

    我们看一下inheritFromWidgetOfExactType方法的源码:

      /// Obtains the nearest widget of the given type, which must be the type of a
      /// concrete [InheritedWidget] subclass, and registers this build context with
      /// that widget such that when that widget changes (or a new widget of that
      /// type is introduced, or the widget goes away), this build context is
      /// rebuilt so that it can obtain new values from that widget.
      
      /// The [aspect] parameter is only used when [targetType] is an
      /// [InheritedWidget] subclasses that supports partial updates, like
      /// [InheritedModel]. It specifies what "aspect" of the inherited
      /// widget this context depends on.
      InheritedWidget inheritFromWidgetOfExactType(Type targetType, { Object aspect });
      
    

    注释说得很清楚,inheritFromWidgetOfExactType是获取指定context下的,最近的指定类型的Widget,并且此Widget必须是InheritedWidget的子类。

    值得注意的是,它是一个静态方法。所以,只要是相同BuildContext我们即可以在任意子节点上,通过这个静态方法,获取到我们的InheritedWidget,然后读取或修改它的共享数据。

    更新通知

    这个方法,决定了是否通知子节点中StatefulWidgetdidChangeDependencies方法是否调用。

      /// Called when a dependency of this [State] object changes.
      ///
      /// For example, if the previous call to [build] referenced an
      /// [InheritedWidget] that later changed, the framework would call this
      /// method to notify this object about the change.
      ///
      /// This method is also called immediately after [initState]. It is safe to
      /// call [BuildContext.inheritFromWidgetOfExactType] from this method.
      ///
      /// Subclasses rarely override this method because the framework always
      /// calls [build] after a dependency changes. Some subclasses do override
      /// this method because they need to do some expensive work (e.g., network
      /// fetches) when their dependencies change, and that work would be too
      /// expensive to do for every build.
      @protected
      @mustCallSuper
      void didChangeDependencies() { }
    

    StatefulWidget的didChangeDependencies方法就是与InheritedWidget配合使用的。只有当InheritedWidget发生更新并且决定通知时,didChangeDependencies才会调用。

    使用场景

    通常,当我们需要在Widget树,由父节点向子节点传递数据时,会使用InheritedWidget。一旦某个节点的Widget继承了InheritedWidget,那么它的子节点,不论深度是多少,都可以获取到继承了InheritedWidget的Widget,并取得其中的数据成员。

    class TextWidget extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return TextWidgetState();
      }
    
    }
    
    class TextWidgetState extends State<TextWidget> {
      @override
      Widget build(BuildContext context) {
        print("refresh text");
        return Text(
            "count : ${MyInheritedWidget.getData(context).data}"
        );
      }
    
      @override
      void didChangeDependencies() {
        super.didChangeDependencies();
        //父或祖先widget中的InheritedWidget改变(updateShouldNotify返回true)时会被调用。
        //如果build中没有依赖InheritedWidget,则此回调不会被调用。
        print("Dependencies change");
      }
    
    }
    

    所以,InheritedWidget适合做某个子树的数据管理Widget。当某个页面、模块或控件依赖一个或一组数据时。我们可以在其上层,创建一个继承了InheritedWidget的数据管理Widget。

    通过这样的方式,至少我们不用对数据进行层层传递。

    相关文章

      网友评论

          本文标题:InheritedWidget使用说明

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