UniVue更新日志:使用ObservableList优化LoopList/LoopGrid组件的使用

embedded/2024/12/23 6:20:40/

github仓库

稳定版本仓库:https://github.com/Avalon712/UniVue

开发版本仓库:https://github.com/Avalon712/UniVue-Develop

UniVue扩展框架-UniVue源生成器仓库:https://github.com/Avalon712/UniVue-SourceGenerator

更新说明

如果大家有在使用之前的版本或学习之前的版本一定要进行更新到至少是今天的版本,因为今天发现了一个过去的版本的一个重大的BUG(就是视图的BindModel()函数有可能会重复生成UIBundle,这个BUG配合LoopList和LoopGrid组件的功能,会导致UIBundle数量一直在重复叠加生成,非常严重的BUG。一定要记得更新。)

组件功能与使用介绍

UniVue中提供的LoopList和LoopGrid组件是UniVue中重要的组件。首先他们都是依赖UGUI的ScrollRect组件实现的可复用Item的滚动视图(即:如果背包有1000个物品,实际上实例化的GameObject的数量=可视域内的行数*可视域内的列数cols+一行或一列的数量,比如:可视域内只能看见6*6个格子,那么实际的生成的GameObject数量为6*7或7*6,至于是6*7还是7*6取决于滚动方向。对于ListWidget生成的数量也是同样的道理即比可视域的数量多一个)。其中ListWidget提供无限滚动的功能(感觉这个功能应该会用得很少,但是考虑到可以使用这个组件的无限循环滚动功能实现轮播图的效果就保留了),GridWidget则没有提供,因为我相信真实项目中一定不会用到一个背包去无限循环滚动的功能。

关于UniVue中使用的所有例子都能在UniVue-Develop(https://github.com/Avalon712/UniVue-Develop)这个仓库中看到。下面是两个组件的使用:

 两个组件都支持水平滚动和垂直滚动。通过右上方的输出调试信息可以看见Views的数量。由于这两个组件会将ScrollRect的Content下的每个Item都创建一个FlexibleView,因此从这个这个View的数量可以看见实际实例化的GameObject数量。

另外这两个组件不依赖任何Unity中的布局组件,而是内部实现得有一套布局逻辑。

注意:ScrollRect的Content这个GameObject的锚点一定要设置合理。content的布局设置如下面的两个图。(同时content下的第一个Item必须存在,且锚点设置必须为左上角,位置为(0,0,0),因为后面实例化其它Item的GameObject时会将第一个Item作为预制体进行实例化)。

垂直滚动时Content的锚点设置类型

水平滚动时Content的锚点设置

Content下的第一个Item的锚点设置

这两个组件再搭配上UniVue的数据模型双向绑定的功能,就能够实现数据的自更新,UI的实时响应。而且实现所有上述的功能大概你需要写的代码数量就是两行。一行创建视图,一行绑定数据。

关于性能方法,这是完全没得说的,我已经优化到极致了。没有使用什么对象池以及其它的功能,关于具体如何实现的,后面再将吧。

但是今天更新的内容一是优化的这两个组件的视图刷新逻辑和数据重新绑定。同时另外一个重大的更新是使用了UniVue中的ObservableList数据结构优化了之前再绑定List数据会对绑定的List数据进行拷贝(本次更新任然保留了这种模式,但是建议大家使用ObervableList的方式)。使用ObservableList能够完全实现数据驱动式。如果不使用ObservableList,采用原来的List方法,可能每次添加新数据、移除新数据、对数据排序、改变数据的顺序你都要进行两步操作:一是改变你自己维护的那么List数据,二是改变组件内部的维护的List数据。这样真的很麻烦,而且会对List进行拷贝的方式,如果要绑定的数据本来就很多,现在还要拷贝一份。我忍受不了这种低效的方式,所有设计了一个新的List集合来优化上面的低效。

ObservableList<T>数据结构的实现

这个集合的实现其实就是对C#自带的List进行包装修饰(装饰器模式),核心功能和List是一样的,但是对List的一些对数据内容的修改进行了封装,能够实现实现当内容发生改变时自动调用回调函数。这个类的使用和List的使用完全一样,List所有支持的操作它都能进行。同时支持注册回调事件、以及实现Java中将List变为一个不可变的集合(变为不可变的集合后,后面对集合内容的修改都会抛出异常)。其中提供的List扩展功能就是IObservableList接口定义的功能。ObservableList<T>这个类的实现代码太长了,建议大家可以去源码中查看,这个类定义在UniVue>Runtime>Utils>Extensions这个目录下,命名空间为UniVue.Utils。

    /// <summary>/// 事件调用顺序:OnAdded | OnRemoved | OnReplaced  ----> OnChanged/// </summary>public interface IObservableList{/// <summary>/// 获得当前回调函数的观察者的id/// </summary>/// <remarks>没有的话将返回int.MinValue</remarks>int CurrentObserverId { get; }int Capacity { get; set; }int Count { get; }V Get<V>(int index);void Set<V>(V item, int index);void Add<V>(V item);bool Remove<V>(V item);bool Contains<V>(V item);void RemoveAt(int index);int IndexOf<V>(V item);void Sort();void Sort<V>(IComparer<V> comparer);/// <summary>/// 当集合内容发生改变时调用(包括元素的增加、删除、替换、顺序改变)/// </summary>void AddListener_OnChanged(int observerId, Action<NotificationMode> onChanged);/// <summary>/// 当有元素被移除时回调(arg0: 被移除的元素 arg1: 被移除元素的索引;)/// </summary>void AddListener_OnRemoved<V>(int observerId, Action<V, int> onRemoved);/// <summary>/// 当有新数据添加时回调/// </summary>void AddListener_OnAdded<V>(int observerId, Action<V> onAdded);/// <summary>/// 当元素被替换时回调。arg0是元素的索引;arg1是替换前的元素;arg2是替换后的元素/// </summary>void AddListener_OnReplaced<V>(int observerId, Action<int, V, V> onReplaced);void ClearObservers();void RemoveListeners(int observerId);/// <summary>/// 当集合内容发生改变时调用(包括元素的增加、删除、替换、顺序改变)/// </summary>void RemoveListener_OnChanged(int observerId);/// <summary>/// 当有元素被移除时回调(arg0: 被移除元素的索引; arg1: 被移除的元素)/// </summary>void RemoveListener_OnRemoved(int observerId);/// <summary>/// 当有新数据添加时回调/// </summary>void RemoveListener_OnAdded(int observerId);/// <summary>/// 当元素被替换时回调。arg0是元素的索引;arg1是替换前的元素;arg2是替换后的元素/// </summary>void RemoveListener_OnReplaced(int observerId);}

关于这种观察者模式装饰器模式等等在UniVue中使用得非常多。以及为了防止各种值类型装箱操作内部有时候会使用很深的装饰器模式以及多态的使用。

下期功能更新预告 

使用SuperGrid组件实现背包物品的拖拽以及将一个背包的物品拖拽到另外一个背包中。


http://www.ppmy.cn/embedded/50136.html

相关文章

QT串口调试助手V2.0(源码全开源)--上位机+多通道波形显示+数据保存(优化波形显示控件)

首先关于Qt的安装和基本配置这里就不做重复说明了&#xff0c;注&#xff1a;本文在Qt5.14基础上完成 完整的项目开源仓库链接在文章末尾 图形控件——qcustomplot QCustomPlot是一个基于Qt框架的开源绘图库&#xff0c;用于创建高质量的二维图表和数据可视化。 QCustomPlot…

ubuntu访问windows共享文件夹

方法: Ubuntu访问Windows共享文件夹的方法-CSDN博客 基于交换机的PC端网络通信_服务器交换机pc端-CSDN博客 补充说明&#xff1a; 在这里面输入&#xff1a; smb://192.168.0.30/WindowsShareToLinux

Java学习 - Docker管理和容器命令 实例

docker管理 查看docker版本&#xff0c;检测是否可用 sudo docker version查看docker 系统信息 sudo docker infodocker容器命令 容器状态 容器标识 容器长uuid容器短uuid容器名字 查看容器状态 sudo docker status [容器标识1] [容器标识2] [容器标识n]深入查看容器信息 su…

Python序列切片中的双冒号[::]

Python提供了可迭代序列的切片操作&#xff1a; a[start: end: step]&#xff1a;即a[开始索引: 结束索引: 步长]&#xff0c;左闭右开&#xff0c;当步长取默认值时&#xff0c;第二个冒号可省略 以下是一些常用的使用示例&#xff1a; a [2, 3, 4, 5, 6]# 取序列全部元素…

如何使用任意浏览器远程访问本地搭建的Jellyfin影音平台

文章目录 前言1. Jellyfin服务网站搭建1.1 Jellyfin下载和安装1.2 Jellyfin网页测试 2.本地网页发布2.1 cpolar的安装和注册2.2 Cpolar云端设置2.3 Cpolar本地设置 3.公网访问测试4. 结语 前言 本文主要分享如何使用Windows电脑本地部署Jellyfin影音服务并结合cpolar内网穿透工…

分数之限下的抉择:深入解析好专业与好学校的选择

随着2024年高考的落幕&#xff0c;无数考生和家长正站在人生的十字路口&#xff0c;面临着分数限制下选择好专业还是好学校的难题。这个选择不仅关系到考生未来的职业道路&#xff0c;更影响着他们的人生轨迹。本文将深入解析这一选择背后的考量因素&#xff0c;为考生和家长提…

不想搭集群,直接用spark

为了完成布置的作业&#xff0c;需要用到spark的本地模式&#xff0c;根本用不到集群&#xff0c;就不想搭建虚拟机&#xff0c;hadoop集群啥的&#xff0c;很繁琐&#xff0c;最后写作业还用不到集群&#xff08;感觉搭建集群对于我完成作业来说没有什么意义&#xff09;&…

Ps:脚本事件管理器

Ps菜单&#xff1a;文件/脚本/脚本事件管理器 Scripts/Script Events Manager 脚本事件管理器 Script Events Manager允许用户将特定的事件&#xff08;如打开、存储或导出文件&#xff09;与 JavaScript 脚本或 Photoshop 动作关联起来&#xff0c;以便在这些事件发生时自动触…