Unity实现TableView

基于Scrollview封装的TableView,实现对视野外的Cell回收利用,减少创建Cell的开销。

核心逻辑如下:

/***************************************动态使用cell核心逻辑开始
**************************************///计算所有cell的坐标信息
private void CaculateCellPosition()
{int cellsCount = _dataSource.NumberOfCellsInTableView(this);if (cellsCount > 0){_cellsPositionsList.Clear();float currentPos = 0;for (int i = 0; i < cellsCount; i++){_cellsPositionsList.Add(currentPos);float rowSize = _dataSource.TableCellSizeForIndex(this, i);currentPos += rowSize;}_cellsPositionsList.Add(currentPos);}
}//更新内嵌容器的size
private void UpdateContentSize()
{int cellsCount = _dataSource.NumberOfCellsInTableView(this);if (cellsCount > 0){float maxPosition = _cellsPositionsList[cellsCount];if (IsHorizontal){if (maxPosition > TableViewSize.width){InnerContainerSizeDelta = maxPosition - TableViewSize.width;}}else {InnerContainerSizeDelta = maxPosition;}}
}//获取指定位置对应cell的索引
private int GetIndexFromOffset(float offset)
{int index = 0;int maxIdx = _dataSource.NumberOfCellsInTableView(this) - 1;index = this.CaculateIndexFromOffset(offset);if (index != INVALID_INDEX){index = Math.Max(0, index);if (index > maxIdx){index = INVALID_INDEX;}}return index;
}//计算指定位置对应cell的索引
private int CaculateIndexFromOffset(float offset)
{int low = 0;int high = _dataSource.NumberOfCellsInTableView(this) - 1;float search = offset;while (high >= low){int index = low + (high - low) / 2;float cellStart = _cellsPositionsList[index];float cellEnd = _cellsPositionsList[index + 1];if (search >= cellStart && search <= cellEnd){return index;}else if (search < cellStart){high = index - 1;}else{low = index + 1;}}if (low <= 0){return 0;}return INVALID_INDEX;
}//更新视野内cell的显示
private void UpdateCellsShow()
{int countOfItems = _dataSource.NumberOfCellsInTableView(this);if (0 == countOfItems){return;}int startIdx = 0, endIdx = 0, idx = 0, maxIdx = 0;float offset = this.GetContentOffset();maxIdx = Mathf.Max(countOfItems - 1, 0);endIdx = this.GetIndexFromOffset(offset);if (endIdx == INVALID_INDEX){endIdx = countOfItems - 1;}offset -= IsHorizontal ? -TableViewSize.width : this.TableViewSize.height;startIdx = this.GetIndexFromOffset(offset);if (startIdx == -1){startIdx = countOfItems - 1;}if (IsHorizontal){//横向与纵向相反int tmp = startIdx;startIdx = endIdx;endIdx = tmp;}//--_usingCellsList.Sort(new TableViewCellComparer());//--检测可回收的cell--BEGINif (_usingCellsList.Count > 0){var cell = _usingCellsList[0];idx = cell.Index;while (idx < startIdx){this.MoveCellOutOfSight(cell);if (_usingCellsList.Count > 0){cell = _usingCellsList[0];idx = cell.Index;}else{break;}}}if (_usingCellsList.Count > 0){var cell = _usingCellsList[_usingCellsList.Count - 1];idx = cell.Index;while (idx <= maxIdx && idx > endIdx){this.MoveCellOutOfSight(cell);if (_usingCellsList.Count > 0){cell = _usingCellsList[_usingCellsList.Count - 1];idx = cell.Index;}else{break;}}}//--检测可回收的cell--ENDfor (int i = startIdx; i <= endIdx; i++){if (_cellUsingIdxs.Contains(i)){continue;}this.UpdateCellByIndex(i);}
}
//更新指定cell的显示
private void UpdateCellByIndex(int index)
{TableViewCell cell = _dataSource.TableCellAtIndex(this, index);cell.SetIndex(index);cell.ClickEvent.RemoveListener(CellDidClick);cell.ClickEvent.AddListener(CellDidClick);if (cell.gameObject.activeSelf == false){cell.gameObject.SetActive(true);}//--float cellSize = _dataSource.TableCellSizeForIndex(this, index);Vector2 pos = new Vector2();if (IsHorizontal){pos.x = _cellsPositionsList[index] - InnerContainerSizeDelta * 0.5f - 0.5f * TableViewSize.width + cellSize * 0.5f;pos.y = 0;}else {pos.x = 0;pos.y = _cellsPositionsList[index] - InnerContainerSizeDelta * 0.5f + cellSize * 0.5f;}cell.gameObject.GetComponent<RectTransform>().anchoredPosition = pos;//--_usingCellsList.Add(cell);_cellUsingIdxs.Add(cell.Index);
}//回收视野外的cell
private void MoveCellOutOfSight(TableViewCell cell)
{_freedCellsStack.Push(cell);_usingCellsList.Remove(cell);_cellUsingIdxs.Remove(cell.Index);cell.ClickEvent.RemoveListener(CellDidClick);cell.ResetCell();
}/***************************************动态使用cell核心逻辑结束
**************************************/

如何使用呢?按照下面的流程操作即可。

1.创建Test 脚本,脚本继承ITableViewDataSource并实现对应的方法。【ITableViewDelegate根据具体情况决定继承与否】
 public interface ITableViewDataSource{int NumberOfCellsInTableView(TableView tableView);float TableCellSizeForIndex(TableView tableView, int index);TableViewCell TableCellAtIndex(TableView tableView, int index);}
 public class Test : MonoBehaviour, ITableViewDataSource, ITableViewDelegate{public TableView tableView;public GameObject hCell = null;public GameObject vCell = null;void Start(){}public int NumberOfCellsInTableView(TableView tableView){return 20;}public float TableCellSizeForIndex(TableView tableView, int index){return 90;}public TableViewCell TableCellAtIndex(TableView tableView, int index){TableViewCell cell = tableView.ReusableCell();if (cell == null){GameObject obj = Instantiate(tableView.IsHorizontal ? hCell : vCell, tableView.InnerContainerContent().transform);cell = obj.GetComponent<TableViewCell>();}cell.name = "Cell " + index;return cell;}public void TableCellClicked(TableView tableView, int index){Debug.Log("TableViewDidSelectCellForRow : " + index);}}
 2.脚本挂载到载体,并绑定对应的变量【HCell和VCell只是为了方便测试横/纵向滚动】

 3.创建TestCell脚本,并继承TableViewCell
  public class TestCell : TableViewCell{public Text txt;public override void UpdateDisplay(){txt.text = "Index " + Index;}}
 4.将TestCell脚本挂载到Scrollview中显示的预制体上
 5.Test脚本中设置TableView的必要属性,调用ReloadData()接口
void Start()
{tableView.Delegate = this;tableView.DataSource = this;tableView.ReloadData();
}

效果如下:  

u3d-demo

项目地址:https://github.com/jjinglover/UnityTableView

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

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

相关文章

利用java8 的 CompletableFuture 优化 Flink 程序,性能提升 50%

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

AI图书推荐:用100个ChatGPT提示词掌握Python编程

《用100个ChatGPT提示词掌握Python编程》&#xff08;ChatGPT:Your Python Coach Mastering the Essentials in 100 Prompts&#xff09; 塞尔吉奥罗哈斯-加莱亚诺&#xff08;Sergio Rojas-Galeano&#xff09;是一位热情的计算机科学家&#xff0c;对人工智能、机器学习、进化…

C++中获取int最大与最小值(补)

上文中&#xff0c;我们学习了C中获取int最大与最小值的两种方法&#xff1a;C库和移位运算&#xff0c;这篇文章将解决在移位运算中遇到的各种报错&#xff0c;并提出一种新的生成int最值的方法 上文链接&#xff1a;http://t.csdnimg.cn/cn7Ad 移位运算取最值常见报错 Dev…

汇编语言(STC89C52)

指令是计算机计算CPU根据人的意图来执行某种操作的命令。一台计算机所执行的全部指令的集合&#xff0c;称为这个CPU的指令系统。而想要使计算机按照人们的要求完成一项工作&#xff0c;就必须让CPU按顺序执行预设的操作&#xff0c;即逐条执行人们编写的指令。这种按照人民要求…

C++ 写的_string类,兼容std::string, MFC CString和 C# 的string

代码例子&#xff1a; using namespace lf; int main() { CString s1 _t("http://www.csdn.net"); _string s2 s1; CString s3 s2; _pcn(s1); _pcn(s2); _pcn(s3); return 0; } 输出&#xff1a; _Str.h /***************************************…

网创教程:WordPress插件网创自动采集并发布

网创教程&#xff1a;WordPress插件网创自动采集并发布 使用插件注意事项&#xff1a; 如果遇到404错误&#xff0c;请先检查并调整网站的伪静态设置&#xff0c;这是最常见的问题。需要定制化服务&#xff0c;请随时联系我。 本次更新内容 我们进行了多项更新和优化&#x…

深入解析kube-scheduler的算法自定义插件

目录 ​编辑 一、问题引入 二、自定义步骤 三、最佳实践考虑 一、问题引入 当涉及到 Kubernetes 集群的调度和资源分配时&#xff0c;kube-scheduler 是一个关键组件。kube-scheduler 负责根据集群的调度策略&#xff0c;将 Pod 分配到适当的节点上。kube-scheduler 默认使…

pyqt6入门案例

效果预览 hello.ui <?xml version"1.0" encoding"UTF-8"?> <ui version"4.0"><class>Dialog</class><widget class"QDialog" name"Dialog"><property name"geometry"><…

android studio接入facebook踩坑1

今天在接入facebook第三方登录的时候&#xff0c;点击登录按钮&#xff0c;APP闪退&#xff0c;并报错 java.lang.RuntimeException Failure delivering result ResultInfo{whonull,request64206,result-1} 新文章链接https://lengmo714.top/facebook1.html 如下图&#xff1a;…

html多节点生成图片并导出zip包

html多节点生成图片并导出zip包 背景 在做项目时遇到一个要将html节点展示的图片列表统一导出为zip包的需求。 难点 将html节点生成图片将多张图片加入zip包中&#xff0c;然后下载 解决html生成图片问题 参考html截图的思路使用 pnpm add html-to-image如何将图片资源生成z…

鸿蒙OS开发:【一次开发,多端部署】(多设备自适应能力)简单介绍

多设备自适应能力 介绍 本示例是《一次开发&#xff0c;多端部署》的配套示例代码&#xff0c;展示了[页面开发的一多能力]&#xff0c;包括自适应布局、响应式布局、典型布局场景以及资源文件使用。 名称简介 开发前请熟悉鸿蒙开发指导文档&#xff1a;gitee.com/li-shizhe…

数据可视化技术头歌测试合集

努力是为了不平庸~ 学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰 目录 时间趋势可视化-柱形图 第1关&#xff1a;“大胃王”比赛数据柱形图绘制——绘制柱形图的基本步骤 任务描述 相关知识 观察和处理数据 绘…

Linux中gcc/g++的基本使用

目录 gcc/g的使用gcc/g是如何生成可执行文件的预处理编译汇编链接 库.o文件是如何与库链接的&#xff1f; debug版本和release版本 gcc/g的使用 在windows中&#xff0c;我们在VS中编写好了代码之后就可以直接在VS中对源码进行编译等操作后运行 而在Linux下&#xff0c;我们可…

LeetCode 279 —— 完全平方数

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 此图利用动态规划进行求解&#xff0c;首先&#xff0c;我们求出小于 n n n 的所有完全平方数&#xff0c;存放在数组 squareNums 中。 定义 dp[n] 为和为 n n n 的完全平方数的最小数量&#xff0c;那么有状态…

vue 展示svg矢量图可缩放拖动

使用插件&#xff1a;svg-pan-zoom <template> <!-- svg图--><div id"svgContainer"></div> </template><script> import svgPanZoom from svg-pan-zoom import svgFile from ../datav/img/220kVscb.svg // 路径根据实际情况调…

计算机组成结构—中断和异常

一、基本概念和分类 计算机在执行程序的过程中&#xff0c;有时会遇到一些异常情况或者特殊请求&#xff1b;这时就需要计算机暂停正在运行的程序&#xff0c;转而先去处理这些异常或特殊请求&#xff0c;处理结束之后再返回程序的断点处继续执行。这种处理方式就被称为 “中断…

顶坚北斗有源终端有什么功能跟用途

顶坚北斗有源终端作为现代卫星导航与通信技术融合的杰出代表&#xff0c;其用途广泛且功能强大。在广袤无垠的偏远山区、深邃的海洋以及荒芜的沙漠中&#xff0c;当用户面临移动通信信号无法覆盖的困境时&#xff0c;北斗有源终端便成为了连接世界的桥梁。 该终端的核心功能之一…

PE文件(六)新增节-添加代码作业

一.手动新增节添加代码 1.当预备条件都满足&#xff0c;节表结尾没有相关数据时&#xff1a; 现在我们将ipmsg.exe用winhex打开&#xff0c;在节的最后新增一个节用于存放我们要增加的数据 注意&#xff1a;飞鸽的文件对齐和内存对齐是一致的 先判断节表末尾到第一个节之间…

奥德彪的幸福VS码农的幸福

奥德彪的幸福 非洲国家布隆迪是一个全球最不发达国家之一&#xff0c;大部分居民以农业为生&#xff0c;其中包括香蕉&#xff0c;人们拿香蕉用来做饭也用来酿酒。 香蕉产地距离布隆迪首都布琼布拉很远&#xff0c;而这个国家又缺乏规模化的物流企业&#xff0c;于是就诞生了…

Linux进程--函数 system 和 popen 的区别

system() 和 popen() 是 C 语言中用于执行外部命令的两个函数&#xff0c;它们的功能类似&#xff0c;但在使用方式和特性上有一些区别。 system() system() 函数允许您在程序中执行外部命令&#xff0c;并等待该命令执行完成后继续执行程序。其基本语法如下&#xff1a; in…