NGUI实现的一套不同大小 Item 的循环滚动代码
测试:
数据 & Item 的 Ctrl :
using UnityEngine; public class ScrollViewItemData
{
public int index;
public string name;
public ScrollViewItemData(int index, string name)
{
this.index = index;
this.name = name;
}
} public class ScrollViewItem : MonoBehaviour
{
UISprite sprBG;
UILabel label;
public ScrollViewItemData data; void Awake()
{
sprBG = GetComponent<UISprite>();
label = transform.Find("Label").GetComponent<UILabel>();
} public Vector3 BgSize
{
get
{
if (null != sprBG)
return sprBG.localSize;
return Vector3.zero;
} } public int BgHeigth
{
get
{
if (null != sprBG)
return sprBG.height;
return ;
}
} public void SetData(ScrollViewItemData data, int index)
{
this.data = data;
label.text = data.name;
sprBG.Update();
//sprBG.ForceUpdate();
this.gameObject.name = index.ToString();
}
}
Item 大小一致的实现代码:
using System.Collections.Generic;
using UnityEngine; public class ScrollViewManager : MonoBehaviour
{
[SerializeField]
GameObject itemPrefab; List<ScrollViewItem> itemList = new List<ScrollViewItem>();
List<ScrollViewItemData> itemDataList = new List<ScrollViewItemData>(); UIScrollView sv;
UIGrid grid; //记录scrollviet上一次的位置,用于判断scrollview的移动方向
float svLastPos = ; //最大y坐标
float maxHeight = ; //最小y坐标
float minHeight = ; // Use this for initialization
void Start()
{
//初始化测试数据 for (int i = ; i < ; i++)
{
itemDataList.Add(new ScrollViewItemData(i, "第 " + (i + ) + " 个元素"));
} sv = transform.GetComponent<UIScrollView>();
grid = transform.Find("Grid").GetComponent<UIGrid>(); Vector2 viewsize = transform.GetComponent<UIPanel>().GetViewSize();
int count = (int)(viewsize.y / grid.cellHeight + );
Debug.Log(count);
for (int i = ; i < count; i++)
{
if (itemDataList.Count <= i)
break; GameObject obj = NGUITools.AddChild(grid.gameObject, itemPrefab); ScrollViewItem item = obj.GetComponent<ScrollViewItem>();
itemList.Add(item); item.SetData(itemDataList[i], i);
}
grid.repositionNow = true;
grid.Reposition(); svLastPos = grid.transform.localPosition.y; maxHeight = viewsize.y / + grid.cellHeight / ; minHeight = -maxHeight; itemPrefab.SetActive(false); } // Update is called once per frame
void Update()
{
float moveDis = sv.transform.localPosition.y - svLastPos;
if (Mathf.Abs(moveDis) > 0.05)
{
bool isup = moveDis > ;
if (isup)
{
while (itemList[].transform.localPosition.y + sv.transform.localPosition.y > maxHeight &&
itemList[itemList.Count - ].data.index < itemDataList.Count - )
{
ScrollViewItem item = itemList[];
item.SetData(itemDataList[itemList[itemList.Count - ].data.index + ], item.data.index); itemList.Add(item);
itemList.RemoveAt(); item.transform.localPosition = itemList[itemList.Count - ].transform.localPosition - new Vector3(, grid.cellHeight, );
}
}
else
{
while (itemList[itemList.Count - ].transform.localPosition.y + sv.transform.localPosition.y < minHeight &&
itemList[].data.index > )
{
ScrollViewItem item = itemList[itemList.Count - ];
item.SetData(itemDataList[itemList[].data.index - ], item.data.index); itemList.Insert(, item);
itemList.RemoveAt(itemList.Count - ); item.transform.localPosition = itemList[].transform.localPosition + new Vector3(, grid.cellHeight, );
}
} svLastPos = sv.transform.localPosition.y;
}
}
}
Item 大小不一致的代码实现:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine; public class GUIScrollViewManager : MonoBehaviour
{
[SerializeField]
GameObject itemPrefab; List<ScrollViewItem> itemList = new List<ScrollViewItem>();
List<ScrollViewItemData> itemDataList = new List<ScrollViewItemData>();
List<String> strList = new List<string>(); UIScrollView sv;
UITable table; //记录scrollviet上一次的位置,用于判断scrollview的移动方向
float svLastPos = ; //最大y坐标
float maxHeight = 288.0f; //最小y坐标
float minHeight = -288.0f; const string tmpStr = "初始化测试数据";
const int Count = ; // Use this for initialization
void Start()
{
//初始化测试数据
System.Random random = new System.Random();
StringBuilder sb = new StringBuilder(); int sbCounter = ;
for (int i = ; i < Count; i++)
{
int tmpCount = random.Next(, );
sbCounter = ;
while (sbCounter < tmpCount)
{
++sbCounter;
sb.Append(tmpStr);
}
itemDataList.Add(new ScrollViewItemData(i, "第 " + (i + ) + " 个元素" + sb.ToString()));
sb.Remove(, sb.Length); } sv = transform.GetComponent<UIScrollView>();
table = transform.Find("Table").GetComponent<UITable>(); int count = ;
for (int i = ; i < count; i++)
{
if (itemDataList.Count <= i)
break; GameObject obj = NGUITools.AddChild(table.gameObject, itemPrefab);
ScrollViewItem item = obj.GetComponent<ScrollViewItem>();
itemList.Add(item); item.SetData(itemDataList[i], i);
} table.Reposition(); itemPrefab.SetActive(false);
} void Update()
{
float moveDis = sv.transform.localPosition.y - svLastPos; if (Mathf.Abs(moveDis) > 0.05)
{
bool isup = moveDis > ;
if (isup)
{
float height = NGUIMath.CalculateRelativeWidgetBounds(itemList[].transform).size.y;
while (itemList[].transform.localPosition.y + sv.transform.localPosition.y - height > maxHeight &&
itemList[itemList.Count - ].data.index < itemDataList.Count - )
{
ScrollViewItem item = itemList[];
item.SetData(itemDataList[itemList[itemList.Count - ].data.index + ], item.data.index); itemList.Add(item);
itemList.RemoveAt(); float _height = NGUIMath.CalculateRelativeWidgetBounds(itemList[itemList.Count - ].transform).size.y;
item.transform.localPosition = itemList[itemList.Count - ].transform.localPosition - new Vector3(, _height + , );
}
}
else
{
while (itemList[itemList.Count - ].transform.localPosition.y + sv.transform.localPosition.y < minHeight &&
itemList[].data.index > )
{
ScrollViewItem item = itemList[itemList.Count - ];
item.SetData(itemDataList[itemList[].data.index - ], item.data.index); itemList.Insert(, item);
itemList.RemoveAt(itemList.Count - ); float _height = NGUIMath.CalculateRelativeWidgetBounds(item.transform).size.y;
item.transform.localPosition = itemList[].transform.localPosition + new Vector3(, _height + , );
} } svLastPos = sv.transform.localPosition.y;
}
}
}
以上两种情况下 Prefab 的结构如下:

效果:

具体到项目中的实现代码(只记录了大致逻辑,具体细节无记录):
using ClientData;
using Modules.UI;
using System;
using System.Collections.Generic;
using UnityEngine; /// <summary>
/// Item 大小可变的动态循环列表实现(只支持竖向,暂且未实现对横向的支持)
/// 该脚本需要挂在 UIScrollView 所在的 gameObject 上
/// </summary>
public class DynamicFlexibleSizeScrollView : MonoBehaviour
{
//定义的一些 delegate 为了,实现组件的通用化,把逻辑的实现下放到具体的实例中
public delegate void OnInitItem(DFSItemCtrl item, DFSItemData data);
public delegate void OnHideAllItem(List<DFSItemCtrl> itemList);
public delegate DFSItemCtrl OnGetItemCtrl();
public delegate void OnRecycleAllChatInfoCell(List<DFSItemCtrl> list); [SerializeField]
Vector2 originalPanelClipOffset = new Vector2(, );
[SerializeField]
Vector3 originalPanelPosition = new Vector3(, , );
[SerializeField]
Vector3 originalTablePosition = new Vector3(, , );
[SerializeField]
float maxHeight; //最大y坐标
[SerializeField]
float minHeight; //最小y坐标
[SerializeField]
int itemCount = ; //创建多少数量的 item 来做循环滚动
[SerializeField]
float offset = 6.0f; //item 中间空出的距离 float svLastPos = ; //记录scrollviet上一次的位置,用于判断scrollview的移动方向
List<DFSItemCtrl> itemList = new List<DFSItemCtrl>();
List<DFSItemData> itemDataList = new List<DFSItemData>();
UIScrollView sv;
UIPanel currUIPanel;
UITable table; //只是在初始化的时候会用到,在滑动的时候,不会再次操作该组件 void InitNGUIComponent()
{
if (null == sv)
sv = GetComponent<UIScrollView>(); if (null != sv && null == currUIPanel)
currUIPanel = sv.panel; if (null == table)
table = GetComponentInChildren<UITable>();
} public float MaxHeight
{
set { maxHeight = value; }
} public float MinHeight
{
set { minHeight = value; }
} public OnInitItem onInitItem; //刷新 item
public OnHideAllItem onHideAllItem; //隐藏所有 item public OnGetItemCtrl getItemCtrl;
public OnRecycleAllChatInfoCell recycleAllChatInfoCell; bool CheckContainData(DFSItemData data)
{
if (null != data)
{
for (int i = , iMax = itemDataList.Count - ; i <= iMax; ++i)
{
if (itemDataList[i].Index == data.Index)
return true;
}
} return false;
} void AddData(DFSItemData data)
{
if (!CheckContainData(data))
{
itemDataList.Add(data);
}
} DFSItemCtrl tmpCtrl = null;
public void ShowSingleItem(DFSItemData data)
{
if (null == data) return; InitNGUIComponent(); AddData(data); if (itemList.Count < itemCount)
{
AddItem(data); if (null != table)
table.Reposition(); if (null != sv)
sv.ResetPosition();
}
else
{
AutoDragUIPanelByData(data);
}
} void AutoDragUIPanelByData(DFSItemData data)
{
if (null != data)
{
if (null != getItemCtrl)
{
//从池中拿出一个 item 计算 panel 需要移动的位置
if (null == tmpCtrl)
tmpCtrl = getItemCtrl(); if (null != tmpCtrl && null != onInitItem)
{
onInitItem(tmpCtrl, data);
float height = NGUIMath.CalculateRelativeWidgetBounds(tmpCtrl.transform).size.y;
Vector2 vec2 = new Vector2(, height + offset);
SetPanelClipOff(vec2);
tmpCtrl.cachedGameObject.SetActive(false);
}
}
}
} void SetPanelClipOff(Vector2 vec2)
{
Vector2 tmpOff = currUIPanel.clipOffset;
tmpOff -= vec2;
currUIPanel.clipOffset = tmpOff; Vector3 tmpPos = currUIPanel.cachedTransform.localPosition;
tmpPos = new Vector3(tmpPos.x, -tmpOff.y, );
currUIPanel.cachedTransform.localPosition = tmpPos;
} public void ShowAllItems(List<DFSItemData> dataList)
{
if (null == dataList) return; svLastPos = ;
InitNGUIComponent(); if (null != sv)
{
currUIPanel.clipOffset = originalPanelClipOffset;
sv.transform.localPosition = originalPanelPosition;
}
if (null != table)
table.transform.localPosition = originalTablePosition; //数据保存
for (int i = , iMax = dataList.Count; i < iMax; ++i)
AddData(dataList[i]); //如果数据数量大于了创建的item数量,自动滑动panel
if (itemDataList.Count > itemCount)
{
int i = itemDataList.Count - itemCount,
iMax = itemDataList.Count;
for (; i < iMax; ++i)
{
AddItem(itemDataList[i]);
}
}
else
{
for (int i = ; i < itemCount; ++i)
{
if (itemDataList.Count <= i) break;
AddItem(itemDataList[i]);
} } ResetPanelStatus();
} void ResetPanelStatus()
{
if (null != table)
table.Reposition();
if (null != sv)
sv.ResetPosition();
} public void RecycleAllChatInfoCell()
{
if (null != recycleAllChatInfoCell)
recycleAllChatInfoCell(itemList);
itemDataList.Clear();
} void AddItem(DFSItemData data)
{
DFSItemCtrl item = null;
if (null != getItemCtrl)
item = getItemCtrl(); if (null != data && null != item && null != onInitItem)
{
this.itemList.Add(item);
item.cachedTransform.parent = table.transform;
onInitItem(item, data);
}
} void Update()
{
if (null == onInitItem || null == itemDataList || itemList.Count <= ) return; float moveDis = sv.transform.localPosition.y - svLastPos; if (Mathf.Abs(moveDis) > 0.05)
{
bool isup = moveDis > ;
if (isup)
{
float height = NGUIMath.CalculateRelativeWidgetBounds(itemList[].transform).size.y;
while (itemList[].transform.localPosition.y + sv.transform.localPosition.y - height > maxHeight &&
itemList[itemList.Count - ].Data.Index < itemDataList.Count - )
{
DFSItemCtrl item = itemList[];
DFSItemData data = itemDataList[itemList[itemList.Count - ].Data.Index + ];
onInitItem(item, data); itemList.Add(item);
itemList.RemoveAt(); float _height = NGUIMath.CalculateRelativeWidgetBounds(itemList[itemList.Count - ].transform).size.y;
item.transform.localPosition = itemList[itemList.Count - ].transform.localPosition - new Vector3(, _height + offset, );
}
}
else
{
while (itemList[itemList.Count - ].transform.localPosition.y + sv.transform.localPosition.y < minHeight &&
itemList[].Data.Index > )
{
DFSItemCtrl item = itemList[itemList.Count - ];
DFSItemData data = itemDataList[itemList[].Data.Index - ];
onInitItem(item, data); itemList.Insert(, item);
itemList.RemoveAt(itemList.Count - ); float _height = NGUIMath.CalculateRelativeWidgetBounds(item.transform).size.y;
item.transform.localPosition = itemList[].transform.localPosition + new Vector3(, _height + offset, );
}
} svLastPos = sv.transform.localPosition.y;
}
}
} /// <summary>
/// 列表中显示的 Item ,应用到项目的时候,实际的 Item 可以继承自该类
/// </summary>
public class DFSItemCtrl : MonoBehaviour
{
protected DFSItemData data; public DFSItemData Data
{
get { return data; }
} GameObject obj = null;
public GameObject cachedGameObject
{
get
{
if (null == obj)
obj = gameObject;
return obj;
}
} Transform tran = null;
public Transform cachedTransform
{
get
{
if (null == tran)
tran = transform;
return tran;
}
} public void ForceUpdateItemSize()
{ } public virtual void SetData(DFSItemData data,params UnityEngine.Object[] list)
{
if (null != data)
{
this.data = data;
ChatInfo info = data as ChatInfo;
this.cachedGameObject.name = info.Index.ToString();
} //强制刷新一下 Item 的大小
ForceUpdateItemSize();
}
} /// <summary>
/// ItemData ,应用到项目的时候,实际的数据可以继承自该类
/// </summary>
public class DFSItemData
{
int index = -; public virtual int Index
{
get { return index; }
set { index = value; }
}
}
效果:

NGUI实现的一套不同大小 Item 的循环滚动代码的更多相关文章
- UWP VirtualizedVariableSizedGridView 支持可虚拟化可变大小Item的View(二)
上篇UWP VirtualizedVariableSizedGridView 支持可虚拟化可变大小Item的View(一) 讲到该控件的需要和设计过程. 这篇讲讲开发过程中一些重要问题解决. 1.支持 ...
- 套接字TCP控制台服务器程序代码示范
套接字TCP控制台服务器程序代码示范 https://blog.csdn.net/txwtech/article/details/90344081
- UWP VirtualizedVariableSizedGridView 支持可虚拟化可变大小Item的View(一)
Boss的需要时这样的,Item是可变大小的,同时根据不同的Window size,来确定Item的结构和大小Window 小的时候是 大的时候是这样的: 当然这size变化的过程中也允许其他结构,我 ...
- 【一套C语言控制台的输出框代码】
效果演示 可以生成一个输出框 首先 要创建输出框,设置输出框风格,可以设置的元素包括: 左上角符号,右上角符号,左下角符号,右下角符号,以及上下左右边界线符号,理论上,只要你电脑能显示的符号,都可以支 ...
- 元素大小-偏移量(offset)客户区大小(client)滚动大小(scroll)
一.偏移量---offset 1.定位父级 在理解偏移大小之前,首先要理解offsetParent.人们并没有把offsetParent翻译为偏移父级,而是翻译成定位父级,很大原因是offsetPar ...
- item上下自动循环滚动显示
//li 上下滚动 (function($){ $.fn.extend({ Scroll:function(opt,callback){ //参数初始化 if(!opt) var opt={}; va ...
- 使用 Spring Boot 搭建一套增删改查(无多余代码)
前言 这是我学习 Spring Boot 的第三篇文章,终于可以见到效果了.错过的同学可以看看之前的文章 我们为什么要学习 Spring Boot Spring Boot 入门详细分析 在入门的基础上 ...
- NGUI 中,长技能图标显示技能Tips的核心代码
需要将技能图标对应的位置Pos赋给Tips即可.下面是计算 Pos 的核心代码: using UnityEngine; public class LgsTest : MonoBehaviour { [ ...
- Android中当item数量超过一定大小RecyclerView高度固定
Android中当item数量超过一定大小时,将RecyclerView高度固定 方法1 直接通过LayoutParams来设定相应高度 ViewGroup.LayoutParams lp = rv. ...
随机推荐
- log4j配置目标到mongodb
首先,具体采用什么技术作为集中式存储方案在99%的应用中应该来说并没有多大区别,最重要的是要定期清理不必要的日志,以及日志格式设计(也可以重写org.log4mongo.MongoDbPatternL ...
- [c/c++] programming之路(7)、数据类型转换、偷钱小程序、进制转换
一.数据类型转换 #include<stdio.h> //某些场合,必须进行数据类型转换,以匹配调用 void main0(){ printf();//printf不管你是什么类型,解析失 ...
- QML的Window与ApplicationWindow
ApplicationWindow需要导入QtQuick.Controls Window需要导入QtQuick.Window . 默认不可见,需要设置visible:true才可见. 主要区别就是Ap ...
- 修改button样式小例子
.toolbar button{ background: none; border:none; padding:0 3px;} <div class="toolbar toolbar- ...
- 我的互联网30年。永远的8U8 永远的Y365
我的互联网30年.永远的8U8 永远的Y365
- tp框架中的一些疑点知识-5
关于vim中的缓存区的前后bp和bn的界定 通过命令ls可以看到 缓存区的 排序. 最开始打开的文件排在最上面, 序号最小. 那么它们就是 更 前 的缓冲区. 序号更前的用bp, 序号靠后的用bn. ...
- Spring Security原理与应用
Spring Security是什么 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配置 ...
- 百度搜索引擎取真实地址-python代码
代码 def parseBaidu(keyword, pagenum): keywordsBaseURL = 'https://www.baidu.com/s?wd=' + str(quote(key ...
- DataTabel 与DataView之间的转化
DataTable转为DataView,或者反之转化, 使用的是文档/试图模型,DataTable可以有多个视图,这样就可以不需要借助List类型对dataTable数据进行筛选或者排序 //Data ...
- LOJ#2427. 「POI2010」珍珠项链 Beads
题目地址 题目链接 题解 不会算复杂度真是致命,暴力枚举k每次计算是n/2+n/3+n/4+...+1的,用调和级数算是\(O(nlogn)\)的... 如果写哈希表的话能够\(O(nlogn)\), ...