Flutter中私有組件可以管理自身狀態(tài),當(dāng)需要跨組件管理狀態(tài)時(shí)可以用到InheritedWidget,InheritedWidget可以共享數(shù)據(jù),數(shù)據(jù)傳遞方式從上往下,它的子組件都可以獲取InheritedWidget中的數(shù)據(jù),實(shí)現(xiàn)了跨組件傳遞。
如組件B和C都是對應(yīng)的子組件,當(dāng)B去修改共享數(shù)據(jù)時(shí),C可以同時(shí)獲取到修改完后的數(shù)據(jù)。同時(shí)還有一個(gè)特性,當(dāng)父組件rebuild的時(shí)間,會觸發(fā)子組件的didChangeDependencies,前提是子組件要用到父組件的共享數(shù)據(jù),在獲取父組件的共享數(shù)據(jù)時(shí),子組件會被注冊,從而可以使didChangeDependencies產(chǎn)生依賴關(guān)系。
updateShouldNotify方法決定子組件的didChangeDependencies是否調(diào)用
import 'package:flu_demo/share_data.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class Model {
int num;
Model(this.num);
}
//共享數(shù)據(jù)
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("第一個(gè)頁面"),),
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('父組件數(shù)據(jù):$_counter'),
_TestC(_counter),
_TestA(),
SizedBox(
height: 20,
),
_TestB(),
SizedBox(
height: 20,
),
RaisedButton(
child: Text("當(dāng)前組件修改 model"),
//每點(diǎn)擊一次,將count自增,然后重新build,ShareDataWidget的data將被更新
onPressed: () => {model.num++}),
SizedBox(
height: 20,
),
RaisedButton(
child: Text("刷新UI 修改 countter"),
//每點(diǎn)擊一次,將count自增,然后重新build,ShareDataWidget的data將被更新
onPressed: () => setState(() => _counter++),
),
RaisedButton(
child: Text("跳轉(zhuǎn)頁面"),
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的數(shù)據(jù):$num');
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
//父或祖先widget中的InheritedWidget改變(updateShouldNotify返回true)時(shí)會被調(diào)用。
//如果build中沒有依賴InheritedWidget,則此回調(diào)不會被調(diào)用。
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的數(shù)據(jù): 1'),
SizedBox(
height: 20,
),
RaisedButton(
onPressed: () => setState(() => m.model.num++),
child: Text("跨組件修改model"),
),
],
);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
//父或祖先widget中的InheritedWidget改變(updateShouldNotify返回true)時(shí)會被調(diào)用。
//如果build中沒有依賴InheritedWidget,則此回調(diào)不會被調(diào)用。
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的數(shù)據(jù): $_count'), //
SizedBox(
height: 20,
),
],
);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
//父或祖先widget中的InheritedWidget改變(updateShouldNotify返回true)時(shí)會被調(diào)用。
//如果build中沒有依賴InheritedWidget,則此回調(diào)不會被調(diào)用。
// 沒有使用InheritedWidget的數(shù)據(jù) 故不會被調(diào)用
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
跨組件修改數(shù)據(jù)時(shí),共享數(shù)據(jù)會變更,不會rebuild,rebuild時(shí)還是需要調(diào)用父級setState,這樣子組件都會rebuild,數(shù)據(jù)展示最新的更改后的值。
當(dāng)在父組件中加入model時(shí),oldwidget和當(dāng)前widget對應(yīng)的model始終不變。原因不是很清楚,可能是model創(chuàng)建后地址不變,新舊widget始終指向該地址。

image.png