如需转载,请注明出处: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 = ; @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 = ; @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回调的!!!

Flutter学习笔记(27)--数据共享(InheritedWidget)的更多相关文章

  1. Flutter学习笔记(3)--Dart变量与基本数据类型

    一.变量 在Dart里面,变量的声明使用var.Object或Dynamic关键字,如下所示: var name = ‘张三’: 在Dart语言里一切皆为对象,所以如果没有将变量初始化,那么它的默认值 ...

  2. Flutter学习笔记(4)--Dart函数

    如需转载,请注明出处:Flutter学习笔记(4)--Dart函数 Dart是一个面向对象的语言,所以函数也是对象,函数属于Function对象,函数可以像参数一样传递给其他函数,这样便于做回调处理: ...

  3. Flutter学习笔记(5)--Dart运算符

    如需转载,请注明出处:Flutter学习笔记(5)--Dart运算符 先给出一个Dart运算符表,接下来在逐个解释和使用.如下:                            描述       ...

  4. Flutter学习笔记(6)--Dart异常处理

    如需转载,请注明出处:Flutter学习笔记(6)--Dart异常处理 异常是表示发生了意外的错误,如果没有捕获异常,引发异常的隔离程序将被挂起,并且程序将被终止: Dart代码可以抛出并捕获异常,但 ...

  5. Flutter学习笔记(8)--Dart面向对象

    如需转载,请注明出处:Flutter学习笔记(7)--Dart异常处理 Dart作为高级语言,支持面向对象的很多特性,并且支持基于mixin的继承方式,基于mixin的继承方式是指:一个类可以继承自多 ...

  6. Flutter学习笔记(9)--组件Widget

    如需转载,请注明出处:Flutter学习笔记(9)--组件Widget 在Flutter中,所有的显示都是Widget,Widget是一切的基础,我们可以通过修改数据,再用setState设置数据(调 ...

  7. Flutter学习笔记(10)--容器组件、图片组件

    如需转载,请注明出处:Flutter学习笔记(10)--容器组件.图片组件 上一篇Flutter学习笔记(9)--组件Widget我们说到了在Flutter中一个非常重要的理念"一切皆为组件 ...

  8. Flutter学习笔记(11)--文本组件、图标及按钮组件

    如需转载,请注明出处:Flutter学习笔记(10)--容器组件.图片组件 文本组件 文本组件(text)负责显示文本和定义显示样式,下表为text常见属性 Text组件属性及描述 属性名 类型 默认 ...

  9. Flutter学习笔记(12)--列表组件

    如需转载,请注明出处:Flutter学习笔记(12)--列表组件 在日常的产品项目需求中,经常会有列表展示类的需求,在Android中常用的做法是收集数据源,然后创建列表适配器Adapter,将数据源 ...

随机推荐

  1. linux_密钥

    使用密钥文件.       这里假设主机A(192.168.100.3)用来获到主机B(192.168.100.4)的文件.   在主机A上执行如下命令来生成配对密钥: ssh-keygen -t r ...

  2. 线程、进程的区别,Java的几个线程状态

    线程.进程的区别        进程的定义:进程就是程序在一个数据集合上的一次执行过程.他与程序的区别在于程序是静态的代码,而进程是动态的执行过程. 进程的特性:1.结构性,进程由程序块.数据块.进程 ...

  3. 在.net core web项目中生成图片验证码

    第1步:添加SkiaSharp包引用 Install-Package SkiaSharp 第2步:编写生成图片验证码的代码 using SkiaSharp; //在类文件头部添加引用 public I ...

  4. JAVA解除tomcat 对浏览器特别字符 | () {} [] 的限制

    1.打开tomcat本机地址打开conf文件夹(一定要关闭Tomcat启动在修改) 2.记事本打开或者编辑软件打开(我这里推荐的编辑软件是以下如图) 打开进去加入这两行代码 3打开server.xml ...

  5. ubuntu中rc.local不执行问题

    解决思路概括起来如下: 1.首先排除脚本自身问题,可以手动点杠执行下试试, 2.脚本确定没问题后,放到开机启动程序引用的路径下,办法如下 2.1.查看系统的运行级别 2.2.到对应运行的rcX.d的目 ...

  6. CodeForces - 940E - Cashback +贪心+DP

    传送门:CodeForces - 940E - Cashback 题意:在一个长度为n的数组中,可以分出长度为 k 连续的多个数组b(每个数组 b 的 k 可不相同),然后,可以对每个数组 b 进行删 ...

  7. codeforces 743D. Chloe and pleasant prizes(树形dp)

    题目链接:http://codeforces.com/contest/743/problem/D 大致思路挺简单的就是找到一个父节点然后再找到其两个字节点总值的最大值. 可以设一个dp[x]表示x节点 ...

  8. 用break语句强制结束循环

    以使用二重循环显示九九乘法表的程序代码为例: #include<stdio.h> int main() { int i,j; ;i<=;i++){ ;j<=;j++) prin ...

  9. 移动端适配,h5网页,手机端适配兼容方案.可以显示真实的1px边框和12px字体大小,dpr浅析

    以前写移动端都是用这段JS解决. (function (doc, win) { // 分辨率Resolution适配 var docEl = doc.documentElement, resizeEv ...

  10. 「每日五分钟,玩转JVM」:对象内存布局

    概览 一个对象根据不同情况可以被划分成两种情况,当对象是一个非数组对象的时候,对象头,实例数据,对齐填充在内存中三分天下,而数组对象中在对象头中多了一个用于描述数组对象长度的部分 对象头 对象头分为两 ...