Flutter中私有组件可以管理自身状态,当需要跨组件管理状态时可以用到InheritedWidget,InheritedWidget可以共享数据,数据传递方式从上往下,它的子组件都可以获取InheritedWidget中的数据,实现了跨组件传递。
如组件B和C都是对应的子组件,当B去修改共享数据时,C可以同时获取到修改完后的数据。同时还有一个特性,当父组件rebuild的时间,会触发子组件的didChangeDependencies,前提是子组件要用到父组件的共享数据,在获取父组件的共享数据时,子组件会被注册,从而可以使didChangeDependencies产生依赖关系。
updateShouldNotify方法决定子组件的didChangeDependencies是否调用
import 'package:flu_demo/share_data.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class Model {
int num;
Model(this.num);
}
//共享数据
class ShareDataWidget extends InheritedWidget {
late final int data;
final Model model;
ShareDataWidget(this.data, this.model, child) : super(child: child);
@override
bool updateShouldNotify(covariant ShareDataWidget oldWidget) {
// TODO: implement updateShouldNotify
// return false;
if (this.data != oldWidget.data) {
var newData = this.data;
var oldData = oldWidget.data;
var newModel = this.model.num;
var oldModel = oldWidget.model.num;
print('this.data : $newData');
print('oldWidget.data : $oldData');
print('this.model : $newModel');
print('oldWidget.model : $oldModel');
return true;
}
return false;
}
static ShareDataWidget? of(BuildContext context) =>
// context.getElementForInheritedWidgetOfExactType() as ShareDataWidget;
context.dependOnInheritedWidgetOfExactType(aspect: ShareDataWidget);
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
Model model = new Model(0);
void _incrementCounter() {
setState(() {
_counter++;
model.num++;
print(_counter);
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
routes: {
'share': (BuildContext context) => new ShareDataPage(),
},
home: Scaffold(
appBar: AppBar(title: Text("第一个页面"),),
body: Container(
width: MediaQuery.of(context).size.width,
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
height: 80,
),
SizedBox(
height: 60,
width: 120,
child: OutlinedButton(
onPressed: () => {_incrementCounter()},
child: Text('刷新父组件'))),
Container(
color: Colors.white,
// 使用了inheritedWidget组件
child: ShareDataWidget(
_counter,
model,
Column(
children: [
SizedBox(
height: 60,
),
Text('父组件数据:$_counter'),
_TestC(_counter),
_TestA(),
SizedBox(
height: 20,
),
_TestB(),
SizedBox(
height: 20,
),
RaisedButton(
child: Text("当前组件修改 model"),
//每点击一次,将count自增,然后重新build,ShareDataWidget的data将被更新
onPressed: () => {model.num++}),
SizedBox(
height: 20,
),
RaisedButton(
child: Text("刷新UI 修改 countter"),
//每点击一次,将count自增,然后重新build,ShareDataWidget的data将被更新
onPressed: () => setState(() => _counter++),
),
RaisedButton(
child: Text("跳转页面"),
onPressed: () => {
// Navigator.pushNamed(context, 'share')
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) =>
ShareDataPage()))
},
),
],
)),
),
],
),
)),
);
}
}
class _TestA extends StatefulWidget {
@override
__TestAState createState() => __TestAState();
}
class __TestAState extends State<_TestA> {
@override
Widget build(BuildContext context) {
// 未使用
// return Text('data');
// 使用
var m = ShareDataWidget.of(context);
var num = m!.model.num;
return Text('A的数据:$num');
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
//父或祖先widget中的InheritedWidget改变(updateShouldNotify返回true)时会被调用。
//如果build中没有依赖InheritedWidget,则此回调不会被调用。
print("Dependencies change A");
}
}
class _TestB extends StatefulWidget {
@override
__TestBState createState() => __TestBState();
}
class __TestBState extends State<_TestB> {
@override
Widget build(BuildContext context) {
print("build B");
var m = ShareDataWidget.of(context);
var num = m!.model.num;
return Column(
children: [
Text('B的数据: 1'),
SizedBox(
height: 20,
),
RaisedButton(
onPressed: () => setState(() => m.model.num++),
child: Text("跨组件修改model"),
),
],
);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
//父或祖先widget中的InheritedWidget改变(updateShouldNotify返回true)时会被调用。
//如果build中没有依赖InheritedWidget,则此回调不会被调用。
print("Dependencies change B");
}
}
class _TestC extends StatefulWidget {
final int count;
_TestC(this.count);
@override
__TestCState createState() => __TestCState();
}
class __TestCState extends State<_TestC> {
@override
Widget build(BuildContext context) {
var _count = widget.count;
return Column(
children: [
Text('C的数据: $_count'), //
SizedBox(
height: 20,
),
],
);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
//父或祖先widget中的InheritedWidget改变(updateShouldNotify返回true)时会被调用。
//如果build中没有依赖InheritedWidget,则此回调不会被调用。
// 没有使用InheritedWidget的数据 故不会被调用
print("Dependencies change C");
}
}
输出日志
flutter: this.data : 15
flutter: oldWidget.data : 14
flutter: this.model : 28
flutter: oldWidget.model : 28
flutter: Dependencies change A
flutter: Dependencies change B
flutter: build B
flutter: didChangeDependencies ShareDataPage
image.png跨组件修改数据时,共享数据会变更,不会rebuild,rebuild时还是需要调用父级setState,这样子组件都会rebuild,数据展示最新的更改后的值。
当在父组件中加入model时,oldwidget和当前widget对应的model始终不变。原因不是很清楚,可能是model创建后地址不变,新旧widget始终指向该地址。
网友评论