Flutter对象状态动态监听Watcher

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

  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使用得内存@overridevoid 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;}///获取uuiddouble 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);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/53653.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GNU-gcc编译选项-1

include目录 -I &#xff0c;比如: -I. -I ./Platform/include -I ./Platform/include/prototypes -I ./tpm/include -I ./tpm/include/prototypes -I ./Simulator/include -I ./Simulator/include/prototypes 编译选项 在GCC编译器中&#xff0c;-D是一个编译选项&…

Java“牵手”天猫商品评论API接口数据,天猫API接口申请指南

天猫商城是一个网上购物平台&#xff0c;售卖各类商品&#xff0c;包括服装、鞋类、家居用品、美妆产品、电子产品等。要获取淘宝商品详情页面评价内容数据&#xff0c;您可以通过开放平台的接口或者直接访问淘宝商城的网页来获取商品详情信息内的评论数据。以下是两种常用方法…

高效实用小工具之Everything

一&#xff0c;简介 有时候我们电脑文件较多时&#xff0c;想快速找到某个文件不是一件容易的事情&#xff0c;实用windows自带的搜索太耗时&#xff0c;效率不高。今天推荐一个用来搜索电脑文件的小工具——Everything&#xff0c;本文将介绍如何安装以及使用everything&…

XXL-JOB

XXL-JOB是一个分布式的任务调度平台。 目的&#xff1a;为了自动完成特定的任务&#xff0c;在约定的特定时间去执行任务的过程。 原因&#xff1a;在spring中有scheduled&#xff0c;放到业务层代码上面也可以。但是其无法做到高可用、防止重复执行&#xff0c;单机处理极限…

uniapp使用uni.chooseLocation()打开地图选择位置

使用uni.chooseLocation()打开地址选择位置&#xff1a; 在Uniapp源码视图进行设置 添加这个属性&#xff1a;"requiredPrivateInfos":["chooseLocation"] ​ </template><view class"location_box"><view class"locatio…

4.12 TCP 连接,一端断电和进程崩溃有什么区别?

目录 TCP keepalive TCP 的保活机制 主机崩溃 进程崩溃 有数据传输的场景 客户端主机宕机&#xff0c;又迅速重启 客户端主机宕机&#xff0c;一直没有重启 TCP连接服务器宕机和进程退出情况总结 TCP keepalive TCP 的保活机制 TCP 保活机制需要通过 socket 接口设置 S…

Mybatis-动态sql和分页

目录 一.什么是Mybatis动态分页 二.mybatis中的动态SQL 在BookMaaper.xml中写sql BookMapper BookBiz接口类 BookBizImpl实现接口类 demo测试类 ​编辑 测试结果 三.mybatis中的模糊查询 mybatis中的#与$有是什么区别 在BookMapper.xml里面建立三个模糊查询 ​编辑 …

用Cmake build OpenCV后,在VS中查看OpenCV源码的方法(环境VS2022+openCV4.8.0) Part II

用Cmake build OpenCV后&#xff0c;在VS中查看OpenCV源码的方法 Part II 用Cmake build OpenCV后&#xff0c;在VS中查看OpenCV源码的方法&#xff08;环境VS2022openCV4.8.0&#xff09; Part I_松下J27的博客-CSDN博客 在上一篇文章中&#xff0c;我用cmake成功的生成了ope…

无涯教程-分类算法 - 逻辑回归

逻辑回归是一种监督学习分类算法&#xff0c;用于预测目标变量的概率&#xff0c;目标或因变量的性质是二分法&#xff0c;这意味着将只有两种可能的类。 简而言之&#xff0c;因变量本质上是二进制的&#xff0c;其数据编码为1(代表成功/是)或0(代表失败/否)。 在数学上&…

【网络】IP网络层和数据链路层

IP协议详解 1.概念 1.1 四层模型 应用层&#xff1a;解决如何传输数据&#xff08;依照什么格式/协议处理数据&#xff09;的问题传输层&#xff1a;解决可靠性问题网络层&#xff1a;数据往哪里传&#xff0c;怎么找到目标主机数据链路层&#xff08;物理层&#xff09;&…

ubuntu下自启动设置,为了开机自启动launch文件

1、书写sh脚本文件 每隔5秒钟启动一个launch文件&#xff0c;也可以直接在一个launch文件中启动多个&#xff0c;这里为了确保启动顺利&#xff0c;添加了一些延时 #! /bin/bash ### BEGIN INIT sleep 5 gnome-terminal -- bash -c "source /opt/ros/melodic/setup.bash…

java八股文面试[数据结构]——ConcurrentHashMap原理

HashMap不是线程安全&#xff1a; 在并发环境下&#xff0c;可能会形成环状链表&#xff08;扩容时可能造成&#xff0c;具体原因自行百度google或查看源码分析&#xff09;&#xff0c;导致get操作时&#xff0c;cpu空转&#xff0c;所以&#xff0c;在并发环境中使用HashMap是…

认识Mybatis的关联关系映射,灵活关联表对象之间的关系

目录 一、概述 ( 1 ) 介绍 ( 2 ) 关联关系映射 ( 3 ) 关联讲述 二、一对一关联映射 2.1 数据库创建 2.2 配置文件 2.3 代码生成 2.4 编写测试 三、一对多关联映射 四 、多对多关联映射 给我们带来的收获 一、概述 ( 1 ) 介绍 关联关系映射是指在数据库中&…

【C++杂货铺】探索vector的底层实现

文章目录 一、STL1.1 什么是STL?1.2 STL的版本1.3 STL的六大组件 二、vector的介绍及使用2.1 vector的介绍2.2 vector的使用2.2.1 vector的定义2.2.2 vector iterator2.2.3 vector空间增长问题2.2.4 vector增删查改 2.3 vector\<char\> 可以替代 string 嘛&#xff1f; …

MyBatis与Spring的集成整合加优化分页功能

目录 一.为什么要将MyBatis和Spring整合&#xff1f;&#xff1f;&#xff1f; 二.配置环境 2.1 pom文件 2.2 xml文件 三.演示举例 四.Aop整合pageHelper 分页插件 今天的分享就到这啦&#xff01;&#xff01;&#xff01; 一.为什么要将MyBatis和Spring整合&#xff1f…

arm: day8

1.中断实验&#xff1a;按键控制led灯 流程&#xff1a; key.h /*************************************************************************> File Name: include/key.h> Created Time: 2023年08月21日 星期一 17时03分20秒***************************************…

Python项目开发案例————学生信息管理系统(附源码)

一、学生信息管理系统 本文使用Python语言开发了一个学生信息管理系统&#xff0c;该系统可以帮助教师快速录入学生的信息&#xff0c;并且对学生的信息进行基本的增、删、改、查操作&#xff1b;还可以实时地将学生的信息保存到磁盘文件中。 1.1 需求分析 为了顺应互联网时代…

图神经网络与分子表征:番外——基组选择

学过高斯软件的人都知道&#xff0c;我们在撰写输入文件 gjf 时需要准备输入【泛函】和【基组】这两个关键词。 【泛函】敲定计算方法&#xff0c;【基组】则类似格点积分中的密度&#xff0c;与计算精度密切相关。 部分研究人员借用高斯中的一系列基组去包装输入几何信息&am…

图论(基础)

知识&#xff1a; 顶点&#xff0c;边 | 权&#xff0c;度数 1.图的种类&#xff1a; 有向图 | 无向图 有环 | 无环 联通性 基础1&#xff1a;图的存储&#xff08;主要是邻接矩阵和邻接表&#xff09; 例一&#xff1a;B3643 图的存储 - 洛谷 | 计算机科学教育新生态 (…

如何实现24/7客户服务自动化?建设智能客服知识库

客户自助服务是指用户通过企业或者第三方建立的网络平台或者终端&#xff0c;实现相关的自定义处理。实现客户服务自动化&#xff0c;对提高客户满意度、维持客户关系至关重要。客户服务自动化可以帮助企业以更快的速度和更高的效率来满足客户的售后服务要求&#xff0c;以进一…