InheritedWidget简介
用于在 widget 树中高效地向下传递数据,允许子组件获取最近Widget树中的InheritedWidget的数据
- 数据共享:在 widget 树中向下共享数据
- 高效更新:当数据变化时,只重建依赖该数据的子 widget
- 自动依赖管理:子 widget 自动"注册"为依赖项(dependOn)
示例
组件结构
子组件TextShowWidget
通过dependOnInheritedWidgetOfExactType()
和NameInheritedWidget
关联,当InputNameWidget
组件TextFiled输入变化
的时,触发NameInheritedWidget变化
,当updateShouldNotify
返回true
,从而通知和NameInheritedWidget关联的组件TextShowWidget变化

代码示例
TestInheritedWidget/AppChildInheritedWidget
在Flutter中Widget是不可变的,InheritedWidget也是一个Widget,所有要更新widget还是得构造一个StatfulWidget,通过setState()来更新, 在 AppChildInheritedWidget中当name发生变化,重新rebuild,来更新NameInheritedWidget数据
, 但是此时的InputShowWidget是通过构造方法传入的,不会改变
scala
class TestInheritedWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("TestInheritedWidget111");
return Scaffold(
appBar: AppBar(
title: Text(
"Inherited",
style: TextStyle(fontSize: 28, color: Colors.white),
),
backgroundColor: Color(0xFFE51BE5),
),
body: AppChildInheritedWidget(child: InputShowWidget()));
}
}
class AppChildInheritedWidget extends StatefulWidget {
final Widget child;
const AppChildInheritedWidget({required this.child, super.key});
@override
State<AppChildInheritedWidget> createState() => _AppChildInheritedWidgetState();
}
class _AppChildInheritedWidgetState extends State<AppChildInheritedWidget> {
String? name;
@override
Widget build(BuildContext context) {
return NameInheritedWidget(
child: widget.child,
name: name,
onNameChange: (value) {
setState(() {
name = value;
});
},
);
}
}
NameInheritedWidget
dependOnInheritedWidgetOfExactType
和 InheritedWidget 产生依赖关系,主动获取数据,当InheritedWidget数据变化时,关联的组件也会自动更新(build),
getInheritedWidgetOfExactType
单纯的获取InheritedWidget的数据,不产生关联,被动获取,
updateShouldNotify
比较新旧widget数据是否一致,true触发更新
typescript
class NameInheritedWidget extends InheritedWidget {
final String? name;
void Function(String? name) onNameChange;
NameInheritedWidget({required super.child, this.name, required this.onNameChange});
static String? of(BuildContext context) {
return context
.dependOnInheritedWidgetOfExactType<NameInheritedWidget>()!
.name;
}
static String? maybe(BuildContext context) {
return context
.dependOnInheritedWidgetOfExactType<NameInheritedWidget>()
?.name;
}
static NameInheritedWidget? getNameInheritedWidget(BuildContext context) {
return context.getInheritedWidgetOfExactType<NameInheritedWidget>();
}
@override
bool updateShouldNotify(covariant NameInheritedWidget oldWidget) {
return oldWidget.name != this.name;
}
}
InputShowWidget
scala
class InputShowWidget extends StatelessWidget {
const InputShowWidget({super.key});
@override
Widget build(BuildContext context) {
print("InputShowWidget222");
return Column(
children: [
Expanded(flex: 2, child: InputNameWidget()),
Expanded(flex: 1, child: TextShowWidget())
],
);
}
}
class TextShowWidget extends StatelessWidget {
const TextShowWidget({super.key});
@override
Widget build(BuildContext context) {
print("TextShowWidget");
var name = NameInheritedWidget.maybe(context) ?? "未知输入";
return Padding(
padding: const EdgeInsets.all(20.0),
child: Center(
child: Text(
name,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.deepOrangeAccent),
)),
);
}
}
InputNameWidget/TextShowWidget
less
class InputNameWidget extends StatefulWidget {
const InputNameWidget({super.key});
@override
State<InputNameWidget> createState() => _InputNameWidgetState();
}
class _InputNameWidgetState extends State<InputNameWidget> {
TextEditingController _textEditingController = TextEditingController(text: "爱好");
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
_textEditingController.dispose();
}
@override
Widget build(BuildContext context) {
print("InputNameWidget333");
return LayoutBuilder(builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
spacing: 20,
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
style: TextStyle(color: Colors.pink),
controller: _textEditingController,
onChanged: (value){
print(value);
NameInheritedWidget.getNameInheritedWidget(context)
?.onNameChange(value);
},
decoration: InputDecoration(
focusColor: Colors.red,
hintText: "请输入",
hintStyle: TextStyle(color: Colors.blueAccent),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: Colors.black)),
filled: true,
fillColor: Color(0xE5BBBBC4)),
),
SizedBox(height: 20,),
FilledButton(
style: ButtonStyle(
backgroundColor: WidgetStatePropertyAll(Colors.black),
padding: WidgetStatePropertyAll(
EdgeInsets.symmetric(vertical: 18)),
shape: WidgetStatePropertyAll(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12)))),
onPressed: () {
NameInheritedWidget.getNameInheritedWidget(context)
?.onNameChange(_textEditingController.text);
},
child: Text("点击"))
],
),
),
),
);
});
}
}
scala
class TextShowWidget extends StatelessWidget {
const TextShowWidget({super.key});
@override
Widget build(BuildContext context) {
print("TextShowWidget");
var name = NameInheritedWidget.maybe(context) ?? "未知输入";
return Padding(
padding: const EdgeInsets.all(20.0),
child: Center(
child: Text(
name,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.deepOrangeAccent),
)),
);
}
}
日志
首次进入所有Widget的build方法全部执行

TextField发生变化,触发底部文字变化
