Flutter状态管理宏定义插件inherited_model_macro的使用
Flutter状态管理宏定义插件inherited_model_macro的使用
宏生成InheritedModel
模板代码并简化状态管理
Dart 宏功能正在开发中,并且目前处于暂停状态,因此此包可能无法正常工作,直到宏功能发布后才会修复。
通过在类中声明字段(以及更新这些字段的方法)并使用[@InheritedModelMacro](/user/InheritedModelMacro)()
进行注解,可以生成完整的InheritedModel
代码(该类必须扩展InheritedModel<String>
):
[@InheritedModelMacro](/user/InheritedModelMacro)()
class LogoModel extends InheritedModel<String> {
final Color? backgroundColor; // 设置值为null也是支持的,在更新方法中
final bool large;
void toggleColor(BuildContext context) {
final newValue = (backgroundColor == null) ? Colors.red : null;
updateState(backgroundColor: newValue); // updateState 是生成的方法
}
void toggleSize(BuildContext context) {
updateState(large: large != true);
}
}
然后像Provider
或InheritedWidget
一样插入生成的持有者类,并提供字段的初始值:
Scaffold(
body: const LogoModelHolder(
backgroundColor: Colors.blue,
large: false,
child: Content(),
)
)
在您的类中将自动生成以下代码:
class LogoModel {
// 获取字段值
static FieldType readField(context) // 对于每个字段
// 获取字段值并订阅其更改。当值更改时,小部件将被重绘
static FieldType watchField(context) // 对于每个字段
// 查找树中最近的实例并更新给定字段
static void update(context, {fields?})
// 直接更新字段
void updateState({fields?})
// 获取树中最近的类实例
static Type getInstance(context)
}
您可以这样使用它:
// 获取当前值并更新它
final currentSize = LogoModel.readLarge(context);
LogoModel.update(context, large: !currentSize);
// 订阅更改
final Color? color = LogoModel.watchBackgroundColor(context);
注意事项:
- 您的类必须扩展
InheritedModel<String>
,直到未来版本中宏功能extendType
不再破坏分析器。 - Dart SDK 版本必须是
^3.5.0-152
或更高版本,并且在analysis_options.yaml
中启用宏并且在构建期间启用宏(文档)。 - 分析器可能会在对宏本身以外的其他项目应用宏时抛出错误,因为生成的代码不存在。与其处理不存在的代码,您可以尝试将此包解压到您的项目中(issue)。
在幕后
持有者类提供了setState
回调给您的类,以便在持有者内部更新值并向下提供给您的类。
InheritedModel
和其他InheritedWidget
一样,用于O(1)树搜索。但是它被标记为@immutable
,所以所有字段都应该是最终的并且不能更改->由持有者提供。
此外,InheritedModel
很有用,因为它允许单独订阅字段的更改。这是通过将字段名称作为aspect
传递给inheritFrom
方法来实现的。这就是为什么您的类必须扩展InheritedModel<String>
。
设置可空字段是通过获取Object stub
来实现的,以处理默认参数为空的情况,并将其与当前字段值进行比较。
其余部分是基本的InheritedModel
模板代码。
示例代码
import 'package:flutter/material.dart';
import 'package:inherited_model_macro/inherited_model_macro.dart';
/// 修改自[InheritedModel文档](https://api.flutter.dev/flutter/widgets/InheritedModel-class.html#widgets.InheritedModel.2)
[@InheritedModelMacro](/user/InheritedModelMacro)()
class LogoModel extends InheritedModel<String> {
final Color? backgroundColor;
final bool large;
void toggleColor(BuildContext context) {
final newValue = (backgroundColor == null) ? Colors.red : null;
updateState(backgroundColor: newValue);
}
}
void main() => runApp(const InheritedModelApp());
class InheritedModelApp extends StatelessWidget {
const InheritedModelApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return const MaterialApp(
home: InheritedModelExample(),
);
}
}
class InheritedModelExample extends StatefulWidget {
const InheritedModelExample({super.key});
[@override](/user/override)
State<InheritedModelExample> createState() => _InheritedModelExampleState();
}
class _InheritedModelExampleState extends State<InheritedModelExample> {
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('InheritedModel Sample')),
body: const LogoModelHolder(
backgroundColor: Colors.blue,
large: false,
child: Content(),
),
);
}
}
class Content extends StatelessWidget {
const Content({
super.key,
});
[@override](/user/override)
Widget build(BuildContext context) {
print("Rebuild content");
return const Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Center(
child: BackgroundWidget(
child: LogoWidget(),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
UpdateBackgroudButton(),
UpdateSizeButton(),
],
)
],
);
}
}
class UpdateBackgroudButton extends StatelessWidget {
const UpdateBackgroudButton({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
print("Rebuild UpdateBackgroudButton");
return ElevatedButton(
onPressed: () => LogoModel.getInstance(context).toggleColor(context),
child: const Text('Update background'),
);
}
}
class UpdateSizeButton extends StatelessWidget {
const UpdateSizeButton({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
print("Rebuild UpdateSizeButton");
return ElevatedButton(
onPressed: () {
final currentSize = LogoModel.readLarge(context);
LogoModel.update(context, large: !currentSize);
},
child: const Text('Resize Logo'),
);
}
}
class BackgroundWidget extends StatelessWidget {
const BackgroundWidget({super.key, required this.child});
final Widget child;
[@override](/user/override)
Widget build(BuildContext context) {
final Color? color = LogoModel.watchBackgroundColor(context);
print("Rebuild BackgroundWidget");
return AnimatedContainer(
padding: const EdgeInsets.all(12.0),
color: color ?? Colors.green,
duration: const Duration(seconds: 2),
curve: Curves.fastOutSlowIn,
child: child,
);
}
}
class LogoWidget extends StatelessWidget {
const LogoWidget({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
final largeLogo = LogoModel.watchLarge(context) == true;
print("Rebuild LogoWidget");
return AnimatedContainer(
padding: const EdgeInsets.all(20.0),
duration: const Duration(seconds: 2),
curve: Curves.fastLinearToSlowEaseIn,
alignment: Alignment.center,
child: FlutterLogo(size: largeLogo ? 200.0 : 100.0),
);
}
}
更多关于Flutter状态管理宏定义插件inherited_model_macro的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter状态管理宏定义插件inherited_model_macro的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
inherited_model_macro
是一个用于 Flutter 的宏定义插件,它旨在简化使用 InheritedModel
进行状态管理的过程。通过使用宏,你可以减少样板代码,使得状态管理的实现更加简洁和高效。
安装
首先,你需要在 pubspec.yaml
中添加 inherited_model_macro
依赖:
dependencies:
flutter:
sdk: flutter
inherited_model_macro: ^1.0.0 # 请检查最新版本
然后运行 flutter pub get
来安装依赖。
基本用法
inherited_model_macro
提供了一个宏 @InheritedModel
,你可以将其应用于一个类,自动生成必要的 InheritedModel
相关代码。
1. 定义一个状态管理类
import 'package:flutter/material.dart';
import 'package:inherited_model_macro/inherited_model_macro.dart';
@InheritedModel()
class CounterModel extends InheritedWidget {
final int count;
CounterModel({
Key? key,
required this.count,
required Widget child,
}) : super(key: key, child: child);
[@override](/user/override)
bool updateShouldNotify(CounterModel oldWidget) {
return oldWidget.count != count;
}
static CounterModel? of(BuildContext context, {bool listen = true}) {
return listen
? context.dependOnInheritedWidgetOfExactType<CounterModel>()
: context.getInheritedWidgetOfExactType<CounterModel>();
}
}
2. 使用 CounterModel
在 Widget 树中传递状态
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: CounterModel(
count: 0,
child: MyHomePage(),
),
);
}
}
class MyHomePage extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
final counterModel = CounterModel.of(context)!;
return Scaffold(
appBar: AppBar(
title: Text('InheritedModel Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'${counterModel.count}',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// TODO: Update the counter
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
3. 更新状态
由于 InheritedModel
是不可变的,你需要通过将其包裹在另一个 Widget 中来更新状态。通常可以使用 StatefulWidget
来实现状态的更新。
class MyApp extends StatefulWidget {
[@override](/user/override)
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
int _count = 0;
void _incrementCounter() {
setState(() {
_count++;
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: CounterModel(
count: _count,
child: MyHomePage(
onIncrement: _incrementCounter,
),
),
);
}
}
class MyHomePage extends StatelessWidget {
final VoidCallback onIncrement;
MyHomePage({required this.onIncrement});
[@override](/user/override)
Widget build(BuildContext context) {
final counterModel = CounterModel.of(context)!;
return Scaffold(
appBar: AppBar(
title: Text('InheritedModel Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'${counterModel.count}',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: onIncrement,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}