Flutter自动绑定插件auto_binding的使用
Flutter自动绑定插件AutoBinding的使用
Setup
首先,确保在你的 pubspec.yaml
文件中添加 auto_binding
插件。
flutter pub add auto_binding
数据提供
系统提供了常见的四种数据提供方式:ModelStatefulWidget
, ModelStatelessWidget
, DataStatefulWidget
, DataStatelessWidget
ModelStatefulWidget
ModelStatefulWidget
提供了一个 model
参数,并给与泛型,可以直接在 build()
中作为 WidgetTree 使用,便于使用已有的数据类型。
/// 组织WidgetTree
@override
Widget build(BuildContext context) {
return ModelStatefulWidget<LoginForm>(
model: LoginForm("", ""),
child: CallModelState(),
);
}
注意:
LoginForm
是ModelStatefulWidget
的模型数据类型。child
是一个普通的 Widget。
ModelStatelessWidget
ModelStatelessWidget
类似于 ModelStatefulWidget
,也提供了 model
参数,可以直接作为 WidgetTree 使用。
@override
Widget build(BuildContext context) {
return ModelStatelessWidget<LoginForm>(
model: LoginForm("", ""),
child: CallModelStatelessWidget(),
);
}
注意:
ModelStatelessWidget
是无状态的,所以每次刷新时model
会被重新创建。ModelStatefulWidget
在刷新后仍然可以保留数据。
DataStatefulWidget
DataStatefulWidget
提供了一个 StatefulWidget
的抽象类,开发者需要编写子类来继承它。自定义的子类中可以自由地添加共享的数据作为成员变量。
/// ExampleForDataStatefulWidget是DataStatefulWidget的子类
class ExampleForDataStatefulWidget extends DataStatefulWidget {
ExampleForDataStatefulWidget({super.key});
@override
ExampleForDataState createState() => ExampleForDataState();
}
/// ExampleForDataState是DataState的子类;
class ExampleForDataState
extends DataState<ExampleForDataStatefulWidget> {
//// 定义共享数据
String username = '';
String password = '';
////
/// CallCallDataStatefulWidget调用方函数
@override
Widget builder(BuildContext context) => const CallDataStatefulWidget();
}
注意:
DataState
提供了自由定义共享数据的代码区域。
DataStatelessWidget
DataStatelessWidget
是一个无状态的抽象类,开发者需要编写其继承类,扩展共享数据项。
/// ModelProviderWidget的继承类
class ExampleForDataStatelessWidget extends DataStatelessWidget {
/// 定义共享数据
final loginForm = LoginForm('', '');
///
/// CallModelProviderWidget是数据调用方
ExampleForDataStatelessWidget()
: super(child: CallDataStatelessWidget());
}
注意:
- 用法与
DataState
相似,也可以自由地定义共享数据。
数据调用
数据调用分为三个步骤:创建构造器,绑定引用,捆绑视图。
创建构造器
通过 context
来创建构造器。
@override
Widget build(BuildContext context) {
var node = Binding.mount(context);
}
注意:
- 绑定的
context
应当遵守范围越小越好,context
即发生变化是刷新的范围。
绑定引用
有两种绑定方式:直接绑定和引用绑定。
final usernameRef = Ref.fromData(
getter: (ModelStatelessWidget<LoginForm> widget) => widget.model.username,
setter: (ModelStatelessWidget<LoginForm> widget, String username) =>
widget.model.username = username,
);
@override
Widget build(BuildContext context) {
var node = Binding.mount(context);
/// 引用绑定: 使用已定义的Ref变量
var username = usernameRef(node);
/// 直接绑定: 提供getter/setter
var password = Ref.fromData(
getter: (ModelStatelessWidget<LoginForm> widget) => widget.model.password,
setter: (ModelStatelessWidget<LoginForm> widget, String password) =>
widget.model.password = password,
).call(node);
...
}
注意:
- 多个上下文使用时,应考虑引用绑定的方式,这样
Ref
变量可以复用。
捆绑视图
使用 binding
填充到某个 WidgetTree
上。
class ExampleForModelStatelessWidget extends StatelessWidget {
final usernameRef = Ref.fromData(
getter: (ModelStatelessWidget<LoginForm> widget) => widget.model.username,
setter: (ModelStatelessWidget<LoginForm> widget, String username) =>
widget.model.username = username,
);
Widget build(BuildContext context) {
/// connecting context
var node = Binding.mount(context);
var username = usernameRef(node);
/// no bind
username.raw;
var password = Ref.fromData(
getter: (ModelStatelessWidget<LoginForm> widget) => widget.model.password,
setter: (ModelStatelessWidget<LoginForm> widget, String password) =>
widget.model.password = password,
).call(node);
return Column(
children: [
const Text('AutoBinding example for ModelStatelessWidget.',
style: TextStyle(
fontSize: 36,
color: Colors.deepOrange,
fontWeight: FontWeight.bold)),
const SizedBox(height: 20),
const Text('轻便的MVVM双向绑定的框架',
style: TextStyle(fontSize: 16, color: Colors.black38)),
const SizedBox(height: 30),
/// binding TextField
BindingTextField(
usernameRef.ref,
/// 传入binding
decoration: const InputDecoration(
labelText: '用户名',
hintText: '请输入用户名',
),
style: const TextStyle(
color: Colors.indigo, fontWeight: FontWeight.bold),
),
const SizedBox(height: 20),
/// binding TextField
BindingTextField(
Ref.fromData(
getter: (ModelStatelessWidget<LoginForm> widget) => widget.model.password,
setter: (ModelStatelessWidget<LoginForm> widget, String password) =>
widget.model.password = password,
).ref,
/// 传入binding
decoration: const InputDecoration(
labelText: '密码',
hintText: '请输入密码',
),
style: const TextStyle(
color: Colors.indigo, fontWeight: FontWeight.bold),
),
const SizedBox(height: 20),
],
const SizedBox(height: 30),
ElevatedButton(
onPressed: () async {
/// write data, to refresh view
username.notifyChange('来自指定值的修改');
password.notifyChange('来自指定值的修改');
},
style: const ButtonStyle(
backgroundColor:
MaterialStatePropertyAll<Color>(Colors.lightBlue),
foregroundColor:
MaterialStatePropertyAll<Color>(Colors.white),
),
child: const Text('更改当前值'),
),
const SizedBox(height: 30),
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(
vertical: 4, horizontal: 10),
color: Colors.blueGrey,
/// binding value
child: Text(
'username = ${username.bindChange()}\npassword = ${password.bindChange()}',
)),
);
}
}
注意:
- 通过
BindingTextField
绑定到TextField
输入框,通过bindChange()
绑定值到Text
视图,value
不会产生绑定。 - 通过
username.notifyChange('来自指定值的修改');
赋值立刻产生页面的刷新。 BindingTextField
还提供了valueToString
与stringToValue
用于更多的格式化输入输出,更多捆绑方式请参见绑定控件篇。
使用macros生成Ref
由于 macros
仍处于实验阶段,暂时无法支持跨包的 Dart Analysis Server
语法解析。
开启macros模式
配置 sdk
版本,3.5.0-152以上。
# pubspec.yaml
environment:
sdk: '>=3.5.0-152 <4.0.0'
启动参数 --enable-experiment=macros
flutter run --enable-experiment=macros
dart run --enable-experiment=macros
编写本地宏
// lib/macros/auto_binding.dart
import 'package:auto_binding/auto_binding.dart' as auto_binding;
macro class RefCodable extends auto_binding.RefCodable {
const RefCodable();
}
macro class IgnoreRefCodable extends auto_binding.IgnoreRefCodable {
const IgnoreRefCodable();
}
使用RefCodable注解
/// define annotation
[@RefCodable](/user/RefCodable)()
class LoginForm {
var username = '123';
String password;
Info info = Info(nickName: '', gender: 'man');
LoginForm(this.username, this.password);
}
[@RefCodable](/user/RefCodable)()
class Info {
String nickName;
String gender;
Info({required this.nickName, required this.gender});
Map<String, dynamic> toJson() => {
'nickName': nickName,
'gender': gender,
};
}
/// call ref
var loginForm = LoginForm('username', 'man');
var ref = loginForm.info.nickNameRef;
var nickName = ref.value; // get value
ref.value = '123'; // set value
var node = Binding.mount(context); // old dependentExecutor dispose
var binding = dataRef(node); // dataRef to binding
var binding = loginForm.info.nickNameRef(node); // ref to binding
var nickName = binding.value; // get value but no bind
binding.value = '123'; // set value but do not update page
binding.bindChange(); // get value and add dependentExecutor
binding.notifyChange('123'); // set value and update page
loginForm.info.nickNameRef(node).bindChange(); // get value and add dependentExecutor
loginForm.info.nickNameRef(node).notifyChange('123'); // set value and update page
loginForm.info.nickNameRef(node).value // get value but no bind
loginForm.info.nickNameRef(node).value = '123'; // set value but do not update page
var nickName = loginForm.info.nickNameRef.bindChange(node: node) // get value and add dependentExecutor
loginForm.Info.nickNameRef.notifyChange(node: node, value: '123'); // set value and update page
bindChangeNotifier(node: node, ref: loginForm.info.nickName, changeNotifier: changeNotifier, notifyListener: notifyListener, onChange: onChange);
bindValueNotifier(node: node, ref: loginForm.info.nickName, valueNotifier: valueNotifier);
更多关于Flutter自动绑定插件auto_binding的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter自动绑定插件auto_binding的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
auto_binding
是一个用于 Flutter 的自动绑定插件,它可以帮助开发者简化在 Flutter 应用中的依赖注入和状态管理。通过使用 auto_binding
,你可以减少手动绑定依赖项的工作量,提高代码的可维护性和可读性。
1. 安装插件
首先,你需要在 pubspec.yaml
文件中添加 auto_binding
依赖:
dependencies:
flutter:
sdk: flutter
auto_binding: ^1.0.0 # 请根据实际情况使用最新版本
然后运行 flutter pub get
来安装依赖。
2. 基本用法
auto_binding
的核心概念是自动绑定依赖项。你可以在应用中定义依赖项,然后通过注解或配置来自动绑定它们。
2.1 创建一个依赖项
假设你有一个 UserService
类,它是一个依赖项:
class UserService {
String getUserName() {
return "John Doe";
}
}
2.2 使用 auto_binding
绑定依赖项
你可以使用 [@Bind](/user/Bind)
注解来标记需要绑定的依赖项:
import 'package:auto_binding/auto_binding.dart';
[@Bind](/user/Bind).singleton
class UserService {
String getUserName() {
return "John Doe";
}
}
2.3 获取绑定的依赖项
在需要使用 UserService
的地方,你可以通过 AutoBinding
来获取它:
import 'package:auto_binding/auto_binding.dart';
void main() {
// 初始化 AutoBinding
AutoBinding.init();
// 获取 UserService 实例
UserService userService = AutoBinding.get<UserService>();
// 使用 UserService
print(userService.getUserName()); // 输出: John Doe
}
3. 高级用法
3.1 依赖注入
auto_binding
支持依赖注入。你可以在构造函数中注入依赖项:
[@Bind](/user/Bind).singleton
class AuthService {
final UserService userService;
AuthService(this.userService);
String getAuthInfo() {
return "Auth Info: ${userService.getUserName()}";
}
}
在使用 AuthService
时,auto_binding
会自动注入 UserService
:
void main() {
AutoBinding.init();
AuthService authService = AutoBinding.get<AuthService>();
print(authService.getAuthInfo()); // 输出: Auth Info: John Doe
}
3.2 Scope 和生命周期管理
auto_binding
支持不同的生命周期管理策略,例如 singleton
(单例)、factory
(每次获取新实例)、lazy
(懒加载)等。
[@Bind](/user/Bind).singleton // 单例模式
class ConfigService {
String getConfig() {
return "Config";
}
}
[@Bind](/user/Bind).factory // 每次获取新实例
class LogService {
String getLog() {
return "Log";
}
}
[@Bind](/user/Bind).lazy // 懒加载
class CacheService {
String getCache() {
return "Cache";
}
}