UIGridView 源码

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;//Introduction: 无限列表
//Content上禁止挂载ContentSizeFilter和LayOutGroup之类组件
[DisallowMultipleComponent]
[RequireComponent(typeof(ScrollRect))]
public class UIGridView : MonoBehaviour
{private Action<Transform, int> _handle;public enum Arrangement{Horizontal = 0,Vertical,}public enum HorizontalAlign{Left,Middle,Right,}public enum VerticalAlign{Top,Middle,Bottom,}public Arrangement arrangement = Arrangement.Vertical;// 当选择水平或垂直流动是有用,指每行/列最大个数public int MaxPerLine{get { return maxPerLine; }set { SetMaxPerLine(value); }}public HorizontalAlign horizontalAlign = HorizontalAlign.Left;public VerticalAlign verticalAlign = VerticalAlign.Top;public Vector2 viewPort;public float rowSpace = 0;public float columuSpace = 0;public float marginTop = 0;public float marginBottom = 0;public float marginLeft = 0;public float marginRight = 0;public int maxPerLine;public int childCount; //需要渲染的总数据个数public GameObject item;public GameObject Child{get { return item; }set { SetItem(value); }}public int ChildCount{get { return childCount; }set { SetChildCount(value, true); }}public Vector2 ViewPort{get { return viewPort; }set { SetViewPort(value); }}ScrollRect scrollRect;RectTransform content;Vector2 itemSize;List<Transform> items;Dictionary<int, int> contains;List<int> outOfContains;int scrollLineIndex; //当前第一个元素索引int totalCount; //在UI中显示的个数(不乘以maxPerLine)Vector2 startPos; //第一个元素所在位置int startIndex; //当前渲染起始坐标int endIndex; //当前渲染结束坐标void Start(){maxPerLine = maxPerLine == 0 ? 1 : maxPerLine;items = new List<Transform>();contains = new Dictionary<int, int>();outOfContains = new List<int>();scrollRect = transform.GetComponent<ScrollRect>();content = scrollRect.content;if (content == null){Debug.Log("ScrollRect " + scrollRect.gameObject.name + " Has No Content, Please Check And Retry.");return;}//viewPort = scrollRect.viewport.rect.size;if (item != null)SetItem(item);content.anchorMax = new Vector2(0, 1);content.anchorMin = new Vector2(0, 1);content.pivot = new Vector2(0, 1);ReBuild();}public void ReBuild(){if (scrollRect == null || content == null || item == null) return;ResetChildren();Vector2 maskSize = viewPort;int count = 0;if (arrangement == Arrangement.Horizontal){count = Mathf.CeilToInt(maskSize.x / itemSize.x) + 1; //横向列数startPos = Vector2.zero;startPos.x = marginLeft;if (verticalAlign == VerticalAlign.Top){startPos.y = -marginTop;}else if (verticalAlign == VerticalAlign.Middle){startPos.y = -(maskSize.y * 0.5f - (itemSize.y * maxPerLine + (maxPerLine - 1) * rowSpace) * 0.5f);}else if (verticalAlign == VerticalAlign.Bottom){startPos.y = -(maskSize.y - marginBottom - itemSize.y * maxPerLine - rowSpace * (maxPerLine - 1));}}else if (arrangement == Arrangement.Vertical){count = Mathf.CeilToInt(maskSize.y / itemSize.y) + 1; //竖向行数startPos = Vector2.zero;startPos.y = -marginTop; //重置开始节点位置if (horizontalAlign == HorizontalAlign.Left){startPos.x = marginLeft;}else if (horizontalAlign == HorizontalAlign.Middle){startPos.x = (maskSize.x * 0.5f - (itemSize.x * maxPerLine + (maxPerLine - 1) * columuSpace) * 0.5f);}else if (horizontalAlign == HorizontalAlign.Right){startPos.x = maskSize.x - marginRight - itemSize.x * maxPerLine - columuSpace * (maxPerLine - 1);}}totalCount = count;SetChildCount(childCount, true);BackTop();scrollRect.onValueChanged.RemoveAllListeners();scrollRect.onValueChanged.AddListener(OnValueChanged);}//列表滚动private void OnValueChanged(Vector2 vec){switch (arrangement){case Arrangement.Horizontal:vec.x = Mathf.Clamp(vec.x, 0, 1);break;case Arrangement.Vertical:vec.y = Mathf.Clamp(vec.y, 0, 1);break;}int curLineIndex = GetCurLineIndex();if (curLineIndex != scrollLineIndex)UpdateRectItem(curLineIndex, false);}private int GetCurLineIndex(){switch (arrangement){case Arrangement.Horizontal:returnMathf.FloorToInt(Mathf.Abs(content.anchoredPosition.x < 0.1f ? content.anchoredPosition.x : 0.1f - marginLeft) /(columuSpace + itemSize.x));case Arrangement.Vertical:returnMathf.FloorToInt(Mathf.Abs(content.anchoredPosition.y > -0.1f ? content.anchoredPosition.y : -0.1f - marginTop) /(rowSpace + itemSize.y));}return 0;}private void UpdateRectItem(int curLineIndex, bool forceRender){if (curLineIndex < 0)return;startIndex = curLineIndex * maxPerLine;endIndex = (curLineIndex + totalCount) * maxPerLine;if (endIndex >= childCount)endIndex = childCount;contains.Clear(); //渲染序号outOfContains.Clear(); //items的索引for (int i = 0; i < items.Count; i++)//如果当前已渲染的item中包含{int index = int.Parse(items[i].gameObject.name);if (index < startIndex || index >= endIndex){outOfContains.Add(i);items[i].gameObject.SetActive(false);}else{items[i].gameObject.SetActive(true);contains.Add(index, i);}}// *************更改渲染****************for (int i = startIndex; i < endIndex; i++){if (!contains.ContainsKey(i)){Transform child = items[outOfContains[0]];outOfContains.RemoveAt(0);child.gameObject.SetActive(true);int row = i / maxPerLine;int col = i % maxPerLine;if (arrangement == Arrangement.Vertical)child.localPosition = startPos +new Vector2(col * itemSize.x + (col) * columuSpace,-row * itemSize.y - (row) * rowSpace);elsechild.localPosition = startPos +new Vector2(row * itemSize.x + (row) * columuSpace,-col * itemSize.y - (col) * rowSpace);child.gameObject.name = i.ToString();if (_handle != null)_handle(child, i);}else if (forceRender){if (_handle != null)_handle(items[contains[i]], i);}}scrollLineIndex = curLineIndex;}/// 移除当前所有private void ResetChildren(){items.Clear();for (int i = 0; i < content.childCount; i++){Transform child = content.GetChild(i);child.gameObject.SetActive(false);}}// 创建新节点private RectTransform CreateItem(int index){Transform child;if (content.childCount > index){child = content.GetChild(index);}else{GameObject obj = GameObject.Instantiate(item) as GameObject;obj.transform.SetParent(content);obj.transform.localScale = Vector3.one;child = obj.transform;}child.gameObject.name = index.ToString();items.Add(child);return child as RectTransform;}// 设置资源public void SetItem(GameObject child){if (child == null) return;this.item = child;RectTransform itemTrans = child.transform as RectTransform;itemTrans.pivot = new Vector2(0, 1);itemSize = itemTrans.sizeDelta;//ReBuild();}// 更新需要渲染的个数public void SetChildCount(int value, bool forceRender){if (value < 0) childCount = 0;else childCount = value;if (totalCount <= 0)//还未初始化return;if (value > items.Count && items.Count < maxPerLine * totalCount){//当前格子数量少于应生成的数量int count = items.Count;int max = value < maxPerLine * totalCount ? value : maxPerLine * totalCount;for (int i = count; i < max; i++){int row = i / maxPerLine;int col = i % maxPerLine;RectTransform child = CreateItem(i);if (arrangement == Arrangement.Vertical)child.localPosition = startPos +new Vector2(col * itemSize.x + (col) * columuSpace,-row * itemSize.y - (row) * rowSpace);elsechild.localPosition = startPos +new Vector2(row * itemSize.x + (row) * columuSpace,-col * itemSize.y - (col) * rowSpace);}}if (content == null) return;int rc = Mathf.CeilToInt((float)childCount / (float)maxPerLine); //设置content的大小if (arrangement == Arrangement.Horizontal){content.sizeDelta = new Vector2(marginLeft + marginRight + itemSize.x * rc + columuSpace * (rc - 1),viewPort.y);if (content.sizeDelta.x > viewPort.x && content.anchoredPosition.x < viewPort.x - content.sizeDelta.x)content.anchoredPosition = new Vector2(viewPort.x - content.sizeDelta.x, content.anchoredPosition.y);}else{content.sizeDelta = new Vector2(viewPort.x, marginTop + marginBottom + itemSize.y * rc + rowSpace * (rc - 1));if (content.sizeDelta.y > viewPort.y && content.anchoredPosition.y > content.sizeDelta.y - viewPort.y)content.anchoredPosition = new Vector2(content.anchoredPosition.x, content.sizeDelta.y - viewPort.y);}UpdateRectItem(GetCurLineIndex(), true);}// 添加子节点public void AddChild(int index){if (index < 0) return;startIndex = scrollLineIndex * maxPerLine;endIndex = (scrollLineIndex + totalCount) * maxPerLine;SetChildCount(childCount + 1, index >= startIndex && index < endIndex);}// 删除子节点public void RemoveChild(int index){if (index < 0 || index >= childCount) return;startIndex = scrollLineIndex * maxPerLine;endIndex = (scrollLineIndex + totalCount) * maxPerLine;SetChildCount(childCount - 1, index >= startIndex && index < endIndex);}// <summary>// 设置显示窗口大小(现在貌似可以废弃了)public void SetViewPort(Vector2 port){if (port == viewPort) return;viewPort = port;//ReBuild();}// 设置行列最大public void SetMaxPerLine(int max){maxPerLine = max;//ReBuild();}// 返回顶部public void BackTop(){content.localPosition = Vector3.zero;UpdateRectItem(0, true);}// 返回底部public void BackBottom(){if (arrangement == Arrangement.Vertical){content.localPosition = new Vector3(0, -viewPort.y + content.sizeDelta.y, 0);}else{content.localPosition = new Vector3(viewPort.x - content.sizeDelta.x, 0);}UpdateRectItem(Mathf.CeilToInt((float)childCount / (float)maxPerLine) - totalCount + 1, true);}public void RefreshViewItem(){UpdateRectItem(scrollLineIndex, true);}public void SetArrangement(int arr){arrangement = (Arrangement)arr;}public void SetHorizontal(int h){horizontalAlign = (HorizontalAlign)h;}public void SetVerticle(int v){verticalAlign = (VerticalAlign)v;}public void AddChangeItemListener(Action<Transform, int> handle){_handle = handle;}
}

示例:
Lua应用示例:

local Tool = require("Tool")local SprogExtendWindow = {}local mediate = nil
local gridView = nil
local extendItem = nil
local extendItemInfo = nil
local sortList = nil
local extendCfgs = nillocal rewardState =
{UNFINISH = 0,  --可领取UNREACH  = 1,  --未达成FINISHED = 2,  --已领取
}function SprogExtendWindow.Init(data)mediate = data-- 创建ITEM实例ResMgr.LoadAssets("prefab", { "SprogExtendItem" },function(objs)extendItem = objs[0]end)extendItemInfo = {} -- 服务器下发数据sortList = {} -- 前端已排序处理,用于显示的数据SprogExtendWindow.InitGridView()SprogExtendWindow.RegistEvents()SprogExtendWindow.UpdateAllExtendInfo()return SprogExtendWindow
endfunction SprogExtendWindow.InitGridView()gridView = mediate:FindChild("Layer_Sprite/panelGroup/extendPanel/bottom/Scroll View"):GetComponent("UIGridView") -- 获取UIGridView组件gridView.maxPerLine = 1gridView.rowSpace = 1gridView:SetItem(extendItem)gridView:SetViewPort(Vector2(565,325))-- 在ScrollView拖动时,UIGridView会回调即将出现的item,客户端只需要填入相应的UI数据.-- PS: 此函数会不停地调用,得考虑性能问题,避免处理过大的数据gridView:AddChangeItemListener(function(transform, index)local index = index + 1if sortList and sortList[index] thenlocal item = sortList[index]Tool.subGetObject(transform, "time", "Text").text = item.config.time .. " " .. item.config.idTool.subGetObject(transform, "content", "Text").text = item.config.nameTool.subGetObject(transform, "image", "Image").sprite = Tool.LoadImgSpriteFromAb("image", item.config.img)SprogExtendWindow.SetStateInfo(item.state, transform)transform:FindChild("Button").onClick = function(obj, eventData)SprogExtendWindow.CheckExtendItemInfo(item.config.id, transform)endendend)endfunction SprogExtendWindow.RegistEvents()mediate:AddClick("Layer_Sprite/panelGroup/extendPanel/top/btn_num", function () log("按钮1")end)mediate:AddClick("Layer_Sprite/panelGroup/extendPanel/top/btn_link", function () log("按钮2")end)mediate:AddClick("Layer_Sprite/panelGroup/extendPanel/top/btn_share", function () log("按钮3")end)
endfunction SprogExtendWindow.InitScrollView()endfunction SprogExtendWindow.UpdateAllExtendInfo()-- TEST,选用临时数据local data = {[1] = {id = 1, type = 1, time = "2020.01.01", name = "床", img = "yxdt_tx1.png", vip = 1, liquanNum = 99999},[2] = {id = 2, type = 1, time = "2020.01.02", name = "前", img = "yxdt_tx1.png", vip = 2, liquanNum = 99999},[3] = {id = 3, type = 1, time = "2020.01.03", name = "明", img = "yxdt_tx1.png", vip = 3, liquanNum = 99999},[4] = {id = 4, type = 1, time = "2020.01.04", name = "月", img = "yxdt_tx1.png", vip = 4, liquanNum = 99999},[5] = {id = 5, type = 1, time = "2020.01.05", name = "光", img = "yxdt_tx1.png", vip = 5, liquanNum = 99999},[6] = {id = 6, type = 1, time = "2020.01.06", name = "床", img = "yxdt_tx1.png", vip = 6, liquanNum = 99999},[7] = {id = 7, type = 1, time = "2020.01.07", name = "前", img = "yxdt_tx1.png", vip = 7, liquanNum = 99999},   [8] = {id = 8, type = 1, time = "2020.01.08", name = "明", img = "yxdt_tx1.png", vip = 8, liquanNum = 99999},[9] = {id = 9, type = 1, time = "2020.01.09", name = "月", img = "yxdt_tx1.png", vip = 9, liquanNum = 99999},[10] = {id = 10, type = 1, time = "2020.01.10", name = "光", img = "yxdt_tx1.png", vip = 10, liquanNum = 99999},[11] = {id = 11, type = 1, time = "2020.01.01", name = "床", img = "yxdt_tx1.png", vip = 1, liquanNum = 99999},[12] = {id = 12, type = 1, time = "2020.01.02", name = "前", img = "yxdt_tx1.png", vip = 2, liquanNum = 99999},[13] = {id = 13, type = 1, time = "2020.01.03", name = "明", img = "yxdt_tx1.png", vip = 3, liquanNum = 99999},[14] = {id = 14, type = 1, time = "2020.01.04", name = "月", img = "yxdt_tx1.png", vip = 4, liquanNum = 99999},[15] = {id = 15, type = 1, time = "2020.01.05", name = "光", img = "yxdt_tx1.png", vip = 5, liquanNum = 99999},[16] = {id = 16, type = 1, time = "2020.01.06", name = "床", img = "yxdt_tx1.png", vip = 6, liquanNum = 99999},[17] = {id = 17, type = 1, time = "2020.01.07", name = "前", img = "yxdt_tx1.png", vip = 7, liquanNum = 99999},   [18] = {id = 18, type = 1, time = "2020.01.08", name = "明", img = "yxdt_tx1.png", vip = 8, liquanNum = 99999},[19] = {id = 19, type = 1, time = "2020.01.09", name = "月", img = "yxdt_tx1.png", vip = 9, liquanNum = 99999},[20] = {id = 20, type = 1, time = "2020.01.10", name = "光", img = "yxdt_tx1.png", vip = 10, liquanNum = 99999},[21] = {id = 21, type = 1, time = "2020.01.01", name = "床", img = "yxdt_tx1.png", vip = 1, liquanNum = 99999},[22] = {id = 22, type = 1, time = "2020.01.02", name = "前", img = "yxdt_tx1.png", vip = 2, liquanNum = 99999},[23] = {id = 23, type = 1, time = "2020.01.03", name = "明", img = "yxdt_tx1.png", vip = 3, liquanNum = 99999},[24] = {id = 24, type = 1, time = "2020.01.04", name = "月", img = "yxdt_tx1.png", vip = 4, liquanNum = 99999},[25] = {id = 25, type = 1, time = "2020.01.05", name = "光", img = "yxdt_tx1.png", vip = 5, liquanNum = 99999}} extendItemInfo = {}for k, v in ipairs(data) doextendItemInfo[v.id] = {   config = v, -- 本地配置state = math.random(0, 2) -- 随机一个状态}endSprogExtendWindow.OnSortAllExtendItem()gridView.ChildCount = #sortList -- 设置当前item总数gridView:ReBuild() -- 启动UIGridView
end-- 整理数据并排序
function SprogExtendWindow.OnSortAllExtendItem()-- 按rewardState分组, 可领取>未达成>已领取local templist = {}for index = 1, 3 dofor _,v in ipairs(extendItemInfo) doif index == v.state + 1 thenif templist[index] == nil thentemplist[index] = {}endtable.insert(templist[index], v)endendend-- 每组按VIP等级排序for _,v in ipairs(templist) dotable.sort(v, function (a, b)return a.config.vip > b.config.vipend)endsortList = {}for _,v in ipairs(templist) dofor _,m in ipairs(v) dotable.insert(sortList, m)endend-- log("排序后列表 " .. tostring(sortList))
endfunction SprogExtendWindow.SetStateInfo(state, obj)local text = nillocal isInteract = nilif state == rewardState.UNREACH thentext = "未达成"isInteract = falseelseif state == rewardState.UNFINISH thentext =  "可领取"isInteract = trueelseif state == rewardState.FINISHED thentext =  "已领取"isInteract = falseendobj.transform:FindChild("Button").interactable = isInteractTool.subGetObject(obj, "Button/Text", "Text").text = text
endfunction SprogExtendWindow.CheckExtendItemInfo(id, obj)if extendItemInfo ~= nil and extendItemInfo[id] ~= nil thenlocal item = extendItemInfo[id]local reqSuccess = function(www)--local data = Json.decode(www.text).datalog("领取成功,data: " .. CC.uu.Dump(data))item.state = 2SprogExtendWindow.SetStateInfo(item.state, obj)endlocal reqFailed = function(err)log("领取失败:" .. tostring(err))end-- 发送请求local Url = Tool.UrlMgr.UrlMapping("http://172.0.0.1:8000/GetTestData", {id = id, channelId = id})Tool.HttpPost(Url, nil, reqSuccess, reqSuccess)end
endfunction SprogExtendWindow.Destroy()endreturn SprogExtendWindow

Unity组件挂载:


无限列表【UIGridView】应用示例相关推荐

  1. html无序列表的滚动效果,html无序列表标签和有序列表标签使用示例

    原标题:html无序列表标签和有序列表标签使用示例 一.上下层列表标签: : 上层dt 下层dd:封装的内容会被自动缩进的效果 复制代码 代码如下: 运动户外 板鞋 篮球鞋 足球鞋 跑步鞋 二.定义有 ...

  2. R语言可视化绘制及PDF使用字体参数列表:查看字体列表、可视化绘制图像中的字体参数列表、字体示例并写入pdf

    R语言可视化绘制及PDF使用字体参数列表:查看字体列表.可视化绘制图像中的字体参数列表.字体示例并写入pdf 目录 R语言可视化绘制及PDF使用字体参数列表:查看字体列表.可视化绘制图像中的字体参数列 ...

  3. android 如何实现无限列表,在Android中解析和创建无限/无限级别的List /子列表中的XML...

    在我的Android Application的服务器端应用程序也由我开发.在这个应用程序Android应用程序从服务器请求一些XML并解析它. XML包含描述应用程序中应该有多少标签的信息,并且每个标 ...

  4. php查询mysql表的行数据类型,PHP 使用mysql_fetch_row 查询获得数据行列表的简单示例...

    对PHP MYSQL mysql_fetch_row –从查询获得数据行列表感兴趣的小伙伴,下面一起跟随512笔记的小编两巴掌来看看吧! mysql_fetch_row用于从mysql数据库中查询数据 ...

  5. Unity UGUI无限列表(Infinite List)

    更新日期:2020年10月16日. Github源码:[点我获取源码] 索引 InfiniteList 使用 创建InfiniteListScrollRect InfiniteListScrollRe ...

  6. acrobat 下拉列表 逻辑_记一次 无限列表 滚动优化

    背景 长列表优化, 是页面性能优化中的一个比较常见的问题,也是面试中的常客. 刚好最近在的项目中, 遇到了一个长列表的性能问题,试过多种方案, 最后得以解决. 今天就给大家分享一下. 正文 场景描述 ...

  7. jq 下拉加载每次只执行一次_记一次 无限列表 滚动优化

    背景 长列表优化, 是页面性能优化中的一个比较常见的问题,也是面试中的常客. 刚好最近在的项目中, 遇到了一个长列表的性能问题,试过多种方案, 最后得以解决. 今天就给大家分享一下. 正文 场景描述 ...

  8. 仿电台网站网页版html代码,DIV+CSS实现电台列表设计的示例代码

    CSS Spite技术:也就是CSS精灵技术,实际上CSS的精灵就是图片里的一个个的图标元素,这些图标可以使按钮.标签以及logo等等.很多网站中都应用了该技术,可有效减少传输请求次数,所需要的图标汇 ...

  9. 自然数 素数 质数_在Java中获取素数的无限列表

    自然数 素数 质数 一个常见的问题是确定数字的素因式分解. 蛮力方法是审判部门( 维基百科 , 可汗学院 ),但是如果必须考虑多个数字,这需要大量的浪费工作. 一种广泛使用的解决方案是Eratosth ...

最新文章

  1. 淘宝装修:第一日 —— 图片轮播
  2. Transformer深至1000层还能稳定训练,微软实习生一作,LSTM之父转发
  3. xdg-open 打开“irc:*”链接
  4. mysql里b树_MySQL-B树/B+树
  5. React全栈之Instagram开源视频教程
  6. 「数据ETL」从数据民工到数据白领蜕变之旅(三)-除了Excel催化剂之外PowerQuery新物种同样值得期待...
  7. 用数组选出最大的数并且排序
  8. 石头剪刀布游戏web_Web开发教程-剪刀石头布
  9. java继续_Java中消除实现继续和面向接口编程
  10. 初识shardingsphere
  11. python3.x和python2.x唯一区别_Python3.x和Python2.x的区别 (转)
  12. POJ 2976 裸的01分数规划
  13. Oracle数据库基本知识
  14. 计算机联锁的应用领域,全电子计算机联锁系统优缺点
  15. 如何彻底删除adobe?adobe官方清理工具怎么用?
  16. Werkflow java_几大工作流引擎对比
  17. 将域名从易名中国(www.ename.cn)转移到中国万网(www.net.cn)
  18. 【HAVENT原创】Salesforce (JSforce) 调用示例
  19. android9彩蛋小米触发不了,小米9成功运行基于Android Q的MIUI系统:初版BUG较多
  20. ue4开关门点击时onclicked事件没有触发的解决方案

热门文章

  1. appendChild元素
  2. 集电极开路、漏极开路
  3. 二维数组打印杨辉三角
  4. hive删除数据、删除分区、删除库表
  5. python 利用TPOT进行自动机器学习 建模
  6. SRM供应商管理系统具有的五大意义
  7. 台球瞄准方法详解(改进版)
  8. 读《计算机程序设计艺术》卷1:基本算法(第3版)
  9. 脑机接口用柔性可伸缩技术及其前景
  10. 杭电OJ 1051(C++)