Flutter对象状态动态监听Watcher

场景:当一个表单需要在表单全部或者特定项赋值后才会让提交按钮可点击。

1.普通实现方式:

Dart 复制代码
    ///场景:检查[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方式实现:

Dart 复制代码
    ///使用[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类:

Dart 复制代码
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类:

Dart 复制代码
///回调
class WatcherCallback<T> {
  ///值改变回调函数,
  ///[object]改变的值。
  final Function(T? object) onChanged;

  WatcherCallback(this.onChanged);
}

Watcher类:

Dart 复制代码
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);
  }
}
相关推荐
passerby60617 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了7 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅7 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
renke33647 小时前
Flutter for OpenHarmony:色彩捕手——基于HSL色轮与感知色差的交互式色觉训练系统
flutter
崔庆才丨静觅8 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment8 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅8 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊8 小时前
jwt介绍
前端
爱敲代码的小鱼8 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax