zoukankan      html  css  js  c++  java
  • Flutter学习笔记(27)--数据共享(InheritedWidget)

    如需转载,请注明出处:Flutter学习笔记(27)--数据共享(InheritedWidget)

    InheritedWidget是Flutter中非常重要的一个功能型组件,它提供了一种数据在widget树中从上到下传递、共享的方式,比如我们在应用的根widget中通过InheritedWidget共享了一个数据,那么我们便可以在任意子widget中来获取该共享的数据。

    前言:假设有这么一个场景,A、B两个组件,A组件有一个数据data,当A组件中的这个数据data发生变化后,B组件需要跟随着做一些处理操作,这时候,如果不通过广播或其他方式通知B组件,我们有什么办法实现这个功能呢?

    didChangeDependencies

    在State对象中,有一个didChangeDependencies回调,这个回调会在“依赖”发生变化时被Flutter Framework调用。而这个“依赖”指的是子widget是否用到了父widget中的InheritedWidget共享数据。如果使用了,则代表子widget依赖InheritedWidget,反之如果没有使用则代表没有依赖。这种机制可以使子组件在所依赖的InheritedWidget发生变化时来更新自身。这也就可以实现我们前面所假设的场景了!

    接下来先给大家看一下整体的代码和效果截图,心里先有一个大概的概念,带着几个概念去思考:1.依赖 2.didChangeDependencies回调 3.InheritedWidge通过什么来通知子widget 

    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class FatherWidget extends InheritedWidget {
      final int data;
    
      FatherWidget({@required this.data, Widget child}) : super(child: child);
    
      //子树通过该方法获取共享数据
      static FatherWidget getData(BuildContext context) {
        return context.inheritFromWidgetOfExactType(FatherWidget);
      }
    
      //该回调决定当data发生变化时,是否通知子树中依赖data的widget
      @override
      bool updateShouldNotify(FatherWidget oldWidget) {
        return oldWidget.data != data;
      }
    }
    
    class ChildWidget extends StatefulWidget {
      @override
      _ChildWidgetState createState() => _ChildWidgetState();
    }
    
    class _ChildWidgetState extends State<ChildWidget> {
      @override
      Widget build(BuildContext context) {
        return new Text(FatherWidget.getData(context).data.toString());
      }
    
      @override
      void didChangeDependencies() {
        super.didChangeDependencies();
        //父或祖先widget中的InheritedWidget改变(updateShouldNotify返回true)时会被调用
        //如果build中没有依赖InheritedWidget,则此回调不会被调用
        print("didChangeDependencies = " +
            FatherWidget.getData(context).data.toString());
      }
    }
    
    class MyApp extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return _MyAppState();
      }
    }
    
    class _MyAppState extends State<MyApp> {
      int count = 0;
    
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'title',
          home: new Scaffold(
            appBar: new AppBar(
              title: new Text('title'),
            ),
            body: new Center(
              child: FatherWidget(
                data: count,
                child: new Column(
                  children: <Widget>[
                    ChildWidget(),
                    new FloatingActionButton(onPressed: _changeCount,child: new Icon(Icons.adjust),),
                  ],
                ),
              ),
            ),
          ),
        );
      }
    
      _changeCount() {
        setState(() {
          ++count;
          print('mCount == ' + count.toString());
        });
      }
    }

     整体代码说明:

    点击按钮后会调用_changeCount()方法,方法内给count数加1,然后通知框架重新build,重新build会给FatherWidget内的data重新赋值,data的数据发生了变化,updateShouldNotify会返回true,通知子widget执行didChangeDependencies回调来处理一下响应操作。

    分块说明一下实现数据共享都需要哪几步:

    1.用于存储共享数据的父Widget,该widget继承InheritedWidget

    class FatherWidget extends InheritedWidget {
      final int data;
    
      FatherWidget({@required this.data, Widget child}) : super(child: child);
    
      //子树通过该方法获取共享数据
      static FatherWidget getData(BuildContext context) {
        return context.inheritFromWidgetOfExactType(FatherWidget);
      }
    
      //该回调决定当data发生变化时,是否通知子树中依赖data的widget
      @override
      bool updateShouldNotify(FatherWidget oldWidget) {
        return oldWidget.data != data;
      }
    }

    2.子widget,用来处理依赖发生变化时的响应处理操作didChangeDependencies

    class ChildWidget extends StatefulWidget {
      @override
      _ChildWidgetState createState() => _ChildWidgetState();
    }
    
    class _ChildWidgetState extends State<ChildWidget> {
      @override
      Widget build(BuildContext context) {
        return new Text(FatherWidget.getData(context).data.toString());
      }
    
      @override
      void didChangeDependencies() {
        super.didChangeDependencies();
        //父或祖先widget中的InheritedWidget改变(updateShouldNotify返回true)时会被调用
        //如果build中没有依赖InheritedWidget,则此回调不会被调用
        print("didChangeDependencies = " +
            FatherWidget.getData(context).data.toString());
      }
    }

    3.FahterWidget和ChildWidget产生依赖关系

      //子树通过该方法获取共享数据
      static FatherWidget getData(BuildContext context) {
        return context.inheritFromWidgetOfExactType(FatherWidget);
      }

    4.数据更新,通过setState来重新build

    class MyApp extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return _MyAppState();
      }
    }
    
    class _MyAppState extends State<MyApp> {
      int count = 0;
    
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'title',
          home: new Scaffold(
            appBar: new AppBar(
              title: new Text('title'),
            ),
            body: new Center(
              child: FatherWidget(
                data: count,
                child: new Column(
                  children: <Widget>[
                    ChildWidget(),
                    new FloatingActionButton(onPressed: _changeCount,child: new Icon(Icons.adjust),),
                  ],
                ),
              ),
            ),
          ),
        );
      }
    
      _changeCount() {
        setState(() {
          ++count;
          print('mCount == ' + count.toString());
        });
      }
    }

    最后需要注意一点,上面说到的依赖前提是两个组件是父、子的关系,我试了一下,如果FatherWidget中没有ChildWidget,只是单纯的使用了FatherWidget的数据的话,是不会触发didChangeDependencies回调的!!!

  • 相关阅读:
    java 变量的初始化顺序
    Asp.net MVC3.0 入门指南 1.简介
    使用EnterpriseLibrary5实现数据的缓存(附完整代码下载)
    js showModalDialog 取得(访问)父窗体的语法
    Asp.net MVC3.0 入门指南 2.控制器Controller
    linq 之入门(一) O/R设计器的使用
    sql2000 示例数据库Northwind的 ER图、字段说明及使用Powerdesigner反向工程方法
    局域网共享文件win7系统
    远程桌面 不能粘贴文本 的解决办法
    解决vs2005控件事件为空白
  • 原文地址:https://www.cnblogs.com/upwgh/p/11593294.html
Copyright © 2011-2022 走看看