场景:当一个表单需要在表单全部或者特定项赋值后才会让提交按钮可点击。
1.普通实现方式:
///场景:检查[test11][test12][test13]均不为空时做一些事情,例如提交按钮变成可点击
String? test11;
String? test12;
int? test13;
///当需要检查[test11][test12][test13]是否全部有值时需要这么做。
///1.给[test11][test12][test13]设置监听,或者在他们赋值的时候每次调用2检查。
///2.检查三个值的状态
if(test11!=null&&test12!=null&&test12!=null){
///print [test11][test12][test13]均不为空。
}
2.使用Watcher方式实现:
///使用[WatchableObject]配合[Watcher]监测
///1.只需要把String、int、bool、等对象用[WatchableObject]代替。
WatchableObject test1 = WatchableObject();
WatchableObject test2 = WatchableObject();
WatchableObject test3 = WatchableObject();
///2.使用[Watcher]单例绑定对象。
Watcher().bindObject([test1, test2, test3]);
///3.检查回调
Watcher().check((allCheck) {
print("?????????????????????=$allCheck");
});
///4.模拟不同时间赋值
Future.delayed(Duration(seconds: 3), () {
test1.setValue("1");
});
Future.delayed(Duration(seconds: 6), () {
test2.setValue("123");
});
Future.delayed(Duration(seconds: 8), () {
test3.setValue(123);
});
///退出界面时清除Watcher使用得内存
@override
void dispose() {
super.dispose();
Watcher().clear();
}
logcat输出:
方式1和方式2都能达到效果,但是方式1需要对每一个变量进行监听,在每一个赋值的地方得检查所有得值是否都已有了值,这样实现的出错率就会变得很高。方式2则是利用变量托管,托管类已实现了对变量的赋值的监听,只要使用托管类WatchableObject包装变量,则可以实时监听到变量的赋值变化,所以代码上,对变量的使用不会再对变量进行任何监听和处理,统一会由Watcher类进行回调处理。方式1的缺点就是代码混乱,容易出错。方式2的优点可以解决方式1的缺点,但是缺点是使用到Watcher的地方,变量必须交给WatchableObject托管,导致定义变量的时候变得麻烦,但是这个只要使用习惯了,确可以忽略该缺点。
喜欢这种方式的或者有需求用得到的朋友来撸代码吧:
WatchableObject类:
import 'dart:math';
import 'package:kq_flutter_widgets/widgets/listener/object_watcher/watcher.dart';
import 'package:kq_flutter_widgets/widgets/listener/object_watcher/watcher_callback.dart';
///可观察对象,
///[T]可观察的对象类型。
///例如:传入的是String,则会持有String对象,
///并可以设置[watcher]观察绑定的String对象值的变化。
class WatchableObject<T> {
T? _watchableObject;
double? _uuid;
///初始值
WatchableObject({T? init}) {
setValue(init);
}
///设置值
void setValue(T? other) {
_watchableObject = Watcher().value(getUuid(), other);
}
///设置观察者
void watcher(WatcherCallback watcherCallback) {
Watcher().watcher(getUuid(), watcherCallback);
}
///获取值
T? value() {
return _watchableObject;
}
///获取uuid
double getUuid() {
return _uuid ??= Random().nextDouble();
}
}
WatcherCallback类:
///回调
class WatcherCallback<T> {
///值改变回调函数,
///[object]改变的值。
final Function(T? object) onChanged;
WatcherCallback(this.onChanged);
}
Watcher类:
import 'package:kq_flutter_widgets/widgets/listener/object_watcher/watchable_object.dart';
import 'package:kq_flutter_widgets/widgets/listener/object_watcher/watcher_callback.dart';
///对象观察者
class Watcher {
Watcher._internal();
factory Watcher() => _instance;
static final Watcher _instance = Watcher._internal();
final Map<double, WatcherCallback> _objectWatchers = {};
final List<WatchableObject> _objects = [];
final Map<double, bool> _bindObjects = {};
///绑定对象,
///[objects]绑定的一组对象。
void bindObject(List<WatchableObject> objects) {
clear();
_objects.addAll(objects);
for (WatchableObject str in objects) {
_bindObjects.putIfAbsent(str.getUuid(), () => _checkObject(str.value()));
}
}
///检查绑定的对象是否已全部赋值,
///[callback]每次赋值都会回调,
///[allCheck]是否全部已赋值,是则返回true,不是则返回false。
void check<T>(Function(bool allCheck) callback) {
for (WatchableObject str in _objects) {
str.watcher(
WatcherCallback(
(object) {
_bindObjects.update(
str.getUuid(),
(value) => _checkObject(object),
);
_realCheck(callback);
},
),
);
}
_realCheck(callback);
}
bool _checkObject<T>(T object) {
return object is String ? object.isNotEmpty : object != null;
}
void _realCheck(Function(bool allCheck) callback) {
bool isAllCheck = true;
_bindObjects.forEach((key, value) {
if (!value) {
isAllCheck = false;
return;
}
});
callback.call(isAllCheck);
}
///清除内存。
void clear() {
_objects.clear();
_bindObjects.clear();
_objectWatchers.clear();
}
///绑定回调执行,
///需要[WatchableObject]对象的[uuid]做为键值获取对象绑定。
T? value<T>(double uuid, T? other) {
_objectWatchers[uuid]?.onChanged(other);
return other;
}
///绑定设置,
///需要[WatchableObject]对象的[uuid]做为键值,
///[watcherCallback]绑定的回调。
void watcher(double uuid, WatcherCallback watcherCallback) {
_objectWatchers.putIfAbsent(uuid, () => watcherCallback);
}
}