说到InheritedWidget,想必大家也都知道这个是Flutter里面非常重要的组件,很多功能场景都是基于InheritedWidget处理实现的,如:Locale、Theme、登录信息以及provider状态管理也是基于InheritedWidget实现
下面先用个小例子,初步学习一下InheritedWidget在不同的widget中通过dependOnInheritedWidgetOfExactType获得共同的数据:
先创建个model
class CNUserModel {
final int count;
const CNUserModel(this.count);
}
再创建一个MyIneritedWidget:
class MyInheritedTest extends InheritedWidget {
final CNUserModel? countModel;
final Function()? add;
MyInheritedTest({Key? key, this.countModel, this.add, Widget? child})
: super(key: key, child: child!);
//静态方法 方便调用
// static MyInheritedTest? of(BuildContext context) {
// return context.dependOnInheritedWidgetOfExactType(aspect: MyInheritedTest());
// }
//静态方法 方便调用
static MyInheritedTest? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType(aspect: MyInheritedTest);
}
//是否重建widget就取决于数据是否相同
@override
bool updateShouldNotify(covariant MyInheritedTest oldWidget) {
// TODO: implement updateShouldNotify
return countModel != oldWidget.countModel;
}
}
这里代码有个地方有个问题,我当时敲的时候,没很注意,就是:context.dependOnInheritedWidgetOfExactType(aspect: MyInheritedTest()),结果就是理所当然的报错:
When the exception was thrown, this was the stack:
#0 new MyInheritedTest (package:getx_demo/first_page.dart:133:37)
#1 MyInheritedTest.of (package:getx_demo/first_page.dart:137:17)
#2 A_View.build (package:getx_demo/first_page.dart:58:43)
#3 StatelessElement.build (package:flutter/src/widgets/framework.dart:4876:49)
#4 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4806:15)
#5 Element.rebuild (package:flutter/src/widgets/framework.dart:4529:5)
#6 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2659:19)
#7 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:891:21)
#8 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:370:5)
#9 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1146:15)
#10 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1083:9)
#11 SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:864:7)
所以,敲的时候要注意哈!!!
创建两个View使用处理和接收一下数据,看是否能共享成:
class A_View extends StatelessWidget {
const A_View({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final inheritedTest = MyInheritedTest.of(context);
final testModel = inheritedTest?.countModel;
debugPrint('A_View中的值: ${testModel?.count}');
return Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
child: GestureDetector(
onTap: inheritedTest?.add,
child: Container(
height: 40,
width: 100,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.blue, borderRadius: BorderRadius.circular(5)),
child: const Text(
'add method',
style: TextStyle(color: Colors.white),
)),
),
);
}
}
class B_View extends StatelessWidget {
const B_View({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final testModel = MyInheritedTest.of(context)?.countModel;
print('B_View中的值: ${testModel?.count}');
return Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
child: Text(
'当前count:${testModel?.count}',
style: const TextStyle(fontSize: 20.0),
),
);
}
}
使用刚刚创建的MyInheritedWidget :
class FirstPage extends StatefulWidget {
const FirstPage({Key? key}) : super(key: key);
@override
_FirstPageState createState() => _FirstPageState();
}
class _FirstPageState extends State<FirstPage> {
CNUserModel? testModel;
@override
void initState() {
// TODO: implement initState
super.initState();
_initData();
}
_initData() {
testModel = const CNUserModel(0);
}
_add() {
setState(() {
testModel = CNUserModel(testModel!.count + 1);
});
}
@override
Widget build(BuildContext context) {
return MyInheritedTest(
countModel: testModel,
add: _add,
child: Scaffold(
appBar: AppBar(
title: const Text("InheritedWidgetTestDemo"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [A_View(), B_View()],
),
),
),
);
}
}
截屏2022-10-19 10.43.38.png
通过控制台日志可以看出,数据操作和共享是成功的了
简单demo到这就完成了,那么demo终究是demo,怎么实际应用到项目中去呢,接下来咱们就稍微修改修改,使用Provider二者结合实现保存和共享用户信息操作:
model修改下,要保存用户信息嘛:
class CNUserModel {
String? name;
int? sex;
CNUserModel({this.name, this.sex});
}
新增一个继承ChangeNotifier的CNUserTool用来接收更新数据:
class CNUserTool extends ChangeNotifier {
CNUserTool(this._userInfo);
CNUserModel _userInfo;
CNUserModel get userInfo => _userInfo;
void update(CNUserModel userInfo) {
_userInfo = userInfo;
notifyListeners();
}
}
MyInheritedTest稍作修改:
class MyInheritedTest extends InheritedWidget {
// final CNUserModel? userModel;
ValueNotifier<CNUserModel>? _valueNotifier;
ValueNotifier<CNUserModel> get valueNotifier => _valueNotifier!;
MyInheritedTest({Key? key, CNUserModel? userModel, Widget? child})
: super(key: key, child: child!) {
_valueNotifier = ValueNotifier<CNUserModel>(userModel!);
}
void updateData(CNUserModel info) {
_valueNotifier?.value = info;
}
//静态方法 方便调用
static MyInheritedTest? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<MyInheritedTest>();
}
@override
bool updateShouldNotify(covariant MyInheritedTest oldWidget) {
return false;
}
}
B_View也稍作修改:
class B_View extends StatefulWidget {
const B_View({Key? key}) : super(key: key);
@override
State<B_View> createState() => _B_ViewState();
}
class _B_ViewState extends State<B_View> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
CNUserTool userTool = Provider.of<CNUserTool>(context);
return Text('name: ${userTool.userInfo.name}\n'
'性别: ${userTool.userInfo.sex! % 2 == 0 ? "男" : "女"}');
}
}
使用:
return Scaffold(
appBar: AppBar(title: const Text('InheritedWidgetDemoPage')),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
B_View(),
const SizedBox(
height: 20,
),
Consumer<CNUserTool>(
builder: (BuildContext context, value, Widget? child) {
return ElevatedButton(
onPressed: () {
value.update(CNUserModel(name: 'lyl', sex: _clickCount++));
},
child: const Text("修改信息"));
},
),
],
),
);
因为是全局共享用户信息嘛,所以入口函数就要处理对应操作:
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
//初始数据值,一般是读取本地存储,这里直接给默认,具体场景具体处理
CNUserModel userModel = CNUserModel(name: "lyl", sex: 2);
return MultiProvider(
providers: [
// ChangeNotifierProvider.value(value: CNUserTool(userModel)),
ChangeNotifierProvider.value(value: CNUserTool(userModel)),
],
child: GetMaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
routes: const {},
),
);
}
}
20221019-112802.gif
通过gif可以在HomePage里面也读取了对应用户信息数据,可见是正常获取以及共享的。至此,实际应用场景也完成了。
生活百般滋味,人生需要笑对~😄
网友评论