Flutter响应式编程插件flutter_reactive_widget的使用
Flutter响应式编程插件flutter_reactive_widget的使用
已弃用
我正在弃用此库,因为我发现了一个在Flutter中创建响应式UI的更简单且更好的机制:请改用flutter_reactive_value库。
此flutter_reactive_widget库的文档和代码仍会托管在此处,但此代码将不再进行进一步开发。
使用
此库提供了一种在Flutter中创建响应式UI的简单机制。
1. 声明状态
使用ReactiveValue<T>(继承自ValueNotifier<T>)声明您的状态:
final counter = ReactiveValue<int>(0);
2. 包装需要对counter.value变化作出反应的代码
使用ReactiveWidget(它接受一个零参数lambda,在ReactiveWidget的build方法中调用该lambda)包装任何需要对counter.value的变化作出反应的代码。
如果在ReactiveWidget的build()方法运行时读取了counter.value,那么ReactiveWidget将开始监听counter.value的变化。(如果该部件被销毁,此监听器将自动移除。)
ReactiveWidget(
() => Text('${counter.value}'),
),
3. 修改counter.value的事件处理程序将触发ReactiveWidget重新构建
修改counter.value的事件处理程序现在将通过在后帧回调中调度setState调用来触发ReactiveWidget重新构建。
IconButton(
icon: const Icon(Icons.plus_one),
onPressed: () {
counter.value++;
},
),
counter.value可以在除build方法之外的任何地方修改(因为build方法不应该改变状态)。
添加库依赖
flutter_reactive_widget托管在pub.dev上。
要能够导入该库,你需要在pubspec.yaml中添加对该库的依赖(如果你想要控制版本,可以将any替换为最新版本),然后运行flutter pub get:
dependencies:
flutter:
sdk: flutter
flutter_reactive_widget: any
在你的代码中导入该库:
import 'package:flutter_reactive_widget/flutter_reactive_widget.dart';
持久化状态的子类PersistentReactiveValue
ReactiveValue每次应用重启时都会重置为其初始值。你可以通过使用PersistentReactiveValue而不是ReactiveValue来持久化值。
首先,在main函数中,你需要初始化WidgetsFlutterBinding,然后需要调用await initPersistentReactiveValue()(定义在flutter_reactive_widget.dart中),这会启动SharedPreferences并从存储中加载任何持久化的值。
main() async {
// 需要按以下顺序执行这两行代码
WidgetsFlutterBinding.ensureInitialized();
await initPersistentReactiveValue();
// 然后运行应用
runApp(App());
}
然后你可以使用PersistentReactiveValue而不是ReactiveValue:
final counter = PersistentReactiveValue<int>(
/* key */ 'counter', /* defaultValue */ 0);
counter.value如果没有被设置过,则会被设置为默认值0;但如果在之前的某个应用运行中已经设置了值,那么这个值将从SharedPreferences中恢复,使用键’counter’。
每当在未来设置counter.value时,不仅任何包裹的ReactiveWidget会被更新,而且新值还会异步写入到SharedPreferences持久化缓存中,使用相同的键。
可以存储null值的子类PersistentReactiveNullableValue
注意,对于PersistentReactiveValue<T>,T不能是可空类型(T?),因为null值无法与SharedPreferences中不存在的值区分开来。
如果你希望能够在SharedPreferences中存储null值(这相当于尝试设置null值时从SharedPreferences中删除键),则可以使用PersistentReactiveNullableValue<T?>。对于此类,defaultValue是可选的。
用于验证的子类ValidatingReactiveValue
ValidatingReactiveValue是ReactiveValue的一个子类,具有一个额外的字段validationError,它本身是一个ReactiveValue<String?>。每当ValidatingReactiveValue的值发生变化时,validationError字段会通过调用传递给ValidatingReactiveValue构造函数的validate函数来更新。例如:
final age = ValidatingReactiveValue<int?>(null,
(a) => a == null ? 'Please specify age' : null);
// 现在你可以在一个`ReactiveWidget`中监听`age.validationError`或`age.value`
手动通知深层值的变化
如果你创建了final set = ReactiveValue<Set<String>>({});然后调用了set.value.add(‘abc’),set的监听器不会收到更改的通知,因为引用本身(即set.value)没有改变。在这种情况下,你可以手动调用监听器,例如:
_addFlag(bool flag) {
bool changed = flag ? set.value.add('flag') : set.value.remove('flag');
if (changed) {
set.notifyListeners();
}
}
在StatefulWidget的State.dispose()方法中移除ReactiveValue监听器
如果你在一个StatefulWidget的State<T>对象的字段中实例化了一个ReactiveValue,确保你的State<T>的dispose()方法调用了ReactiveValue的dispose()方法来移除所有监听器,当部件被销毁时,以防止内存泄漏。
生命周期和状态存储位置
如果你想让ReactiveValue在整个应用生命周期内存在,可以参考这篇Medium文章中关于如何使用GetIt组织应用状态的好建议。应用于flutter_reactive_widget:
main.dart
从main中调用setUpGetIt():
import 'package:my_app/pages/home_page.dart';
import './service_locator.dart';
main() async {
WidgetsFlutterBinding.ensureInitialized();
await initPersistentReactiveValue();
// 注册状态单例(定义在service_locator.dart)
setUpGetIt();
runApp(HomePage());
}
service_locator.dart
使用GetIt将所有包含状态的类注册为单例,每个页面一个状态类(即为页面home_page.dart创建home_page_state.dart):
import 'package:my_app/pages/home_page_state.dart';
import 'package:get_it/get_it.dart';
final getIt = GetIt.instance;
void setUpGetIt() {
getIt.registerLazySingleton<HomePageState>(() => HomePageState());
}
pages/home_page_state.dart
定义每个状态类:
import 'package:flutter_reactive_widget/flutter_reactive_widget.dart';
/// HomePage的持久状态
class HomePageState {
final count = PersistentReactiveValue<int>('count', 0);
}
pages/home_page.dart
使用GetIt.instance<T>()(或getIt<T>,如果你导入了service_locator.dart)获取你需要读取状态的状态单例类实例:
import 'package:my_app/pages/home_page_state.dart';
import 'package:flutter_reactive_widget/flutter_reactive_widget.dart';
import 'package:flutter/material.dart';
import './service_locator.dart';
// 获取页面的状态
final _homePageState = getIt<HomePageState>();
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('HomeView'),
centerTitle: true,
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ReactiveWidget(
() => Text(
'${_homePageState.count.value}',
style: const TextStyle(fontSize: 20),
),
),
IconButton(
icon: const Icon(Icons.plus_one),
onPressed: () {
_homePageState.count.value++;
},
),
],
),
);
}
}
更多关于Flutter响应式编程插件flutter_reactive_widget的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter响应式编程插件flutter_reactive_widget的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何使用Flutter响应式编程插件flutter_reactive_widget的代码案例。这个插件使得在Flutter中进行响应式编程变得更加简单和直观。
首先,确保你已经在pubspec.yaml文件中添加了flutter_reactive_widget依赖:
dependencies:
flutter:
sdk: flutter
flutter_reactive_widget: ^x.y.z # 请替换为最新版本号
然后运行flutter pub get来安装依赖。
以下是一个简单的示例,展示如何使用flutter_reactive_widget进行响应式编程。在这个例子中,我们将使用ReactiveTextField来创建一个响应式文本字段,并实时显示输入内容。
import 'package:flutter/material.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart'; // 注意:实际包名可能有所不同,这里仅作为示例
import 'package:reactive_forms/reactive_forms.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _formGroup = fb.group({
'username': ['', Validators.required],
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Reactive Widgets Example'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: ReactiveForm(
formGroup: _formGroup,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
ReactiveTextField<String>(
formControlName: 'username',
decoration: InputDecoration(
labelText: 'Username',
),
),
SizedBox(height: 16),
Text(
'You entered: ${_formGroup.value['username'] ?? ''}',
style: TextStyle(fontSize: 18),
),
],
),
),
),
);
}
}
在这个例子中,我们做了以下几件事情:
-
创建表单组:使用
fb.group创建一个表单组,并定义了一个名为username的表单控件,它有一个初始值和一个验证器(Validators.required)。 -
构建UI:使用
ReactiveForm包装表单,并在其内部使用ReactiveTextField创建一个响应式文本字段。formControlName属性将文本字段与表单组中的username表单控件绑定。 -
显示输入内容:通过访问
_formGroup.value['username']实时显示用户输入的内容。
注意:flutter_reactive_widget插件实际上依赖于reactive_forms库来处理表单控件和验证。因此,确保你也添加了reactive_forms依赖。
dependencies:
reactive_forms: ^x.y.z # 请替换为最新版本号
这个示例展示了如何使用flutter_reactive_widget(通过reactive_forms)进行基本的响应式表单编程。你可以根据需求扩展这个示例,添加更多的表单控件和验证逻辑。

