NGUI ScrollView 循环 Item 实现性能优化
今天来说说一直都让我在项目中头疼的其中一个问题,NGUI 的scrollView 列表性能问题,实现循环使用item减少性能上的开销。
希望能够给其他同学们使用和提供一个我个人的思路,这个写的不是太完美,目前我在项目中使用了,希望大神能够给更多的建议来优化scrollView.
思 路:通过调整item位置来实现item循环使用,在通过delegate来实现数据刷新
功 能:
SetGrid(int imax, ScrollGridSetItem sc)
NextIndex()
PreIndex()
GotoIndex(int index)
ClearChild()
上代码:
/***
****************** scrollView 循环 item 减少性能消耗 ************
*@2015/03/31
*@author fastHro
*
*基于NGUI Version 3.7.7
*使用说明:在scrollView 下新建空物体,然后把此脚本挂在上面然后设置相关属性.
*注意:scrollGrid 下不需要有item ,由脚本自动创建关联的item
* 刷新item数据通过 委托函数scrollGridSetItem 来设置
*
*/
using UnityEngine;
using System.Collections; public class ScrollGrid : MonoBehaviour {
public delegate void ScrollGridSetItem(Transform[] trans, int start, int end);
/** @index -1 start, 0 start and end, 1 end, 2 center */
public delegate void ScrollGridMessage(int index);
private ScrollGridSetItem scrollGridSetItem;
private ScrollGridMessage scrollGridMessage;
#region 外部数据
/** 最多显示几个 */
public int defaultShowMaxLine;
/** 默认生成几个 */
public int defaultMaxLine;
/** 每一行的间距 */
public int space;
/** 每一行的size */
public Vector2 size; /** gotoIndex 速率 */
public float autoVelocity = 8f;
/** 当数据个数小于defaultMaxLine 列表是否可以移动 */
public bool moveScrollViewLessMaxLine = true;
/** 每次滑动之后是否使item显示在中心 */
public bool centerScrollViewOnChild = false;
#endregion #region 内部数据
private int indexStar = ;
private int indexEnd = ;
private int indexMax = ;
private Vector3 panelPos = Vector3.zero;
private int lastIndex = ;
private int showStartIndex = ;
#endregion #region scrollView
private UIPanel panel;
private UIScrollView sView;
/** 列表的 cliping size */
public Vector2 vSize;
/** 列表移动方式 */
private UIScrollView.Movement movement;
private Transform panelTransfrom;
#endregion #region item
public GameObject ItemPrefab;
private Transform[] itemTrans;
#endregion void Awake()
{
sView = transform.GetComponentInParent<UIScrollView> ();
panel = sView.transform.GetComponentInParent<UIPanel> ();
panelTransfrom = panel.gameObject.transform;
} #region init
/** 初始化设置 */
public void SetGrid(int imax, ScrollGridSetItem sc)
{
if (!moveScrollViewLessMaxLine) {
if(imax < defaultShowMaxLine)
{
sView.enabled = false;
}
}
if (defaultMaxLine > imax) {
defaultMaxLine = imax;
}
initGrid ();
indexMax = imax;
scrollGridSetItem = sc;
if (scrollGridSetItem != null) {
scrollGridSetItem(itemTrans, indexStar, indexEnd);
}
SetMessage ();
} public void SetGrid(int imax, ScrollGridSetItem sc, ScrollGridMessage sm)
{
scrollGridMessage = sm;
SetGrid (imax, sc);
} /** 向后滑动一格 */
public void NextIndex()
{
int ix = GetShowStartIndex ();
//Debug.Log ("next = " + ix);
GotoIndex (ix + );
} /** 向前滑动一格 */
public void PreIndex()
{
int ix = GetShowStartIndex ();
//Debug.Log ("pre = " + ix);
GotoIndex (ix - );
} /**直接跳到指定位置*/
public void GotoIndex(int index)
{
if (index < ) {
return;
}
if (index > indexMax - defaultShowMaxLine) {
return;
}
float ip = GetPanelPositionByIndex (index);
ip = Mathf.Abs (ip);
Vector3 v3 = Vector3.zero;
Vector2 v2 = Vector2.zero; if(movement == UIScrollView.Movement.Horizontal)
{
v3.x = panel.clipSoftness.x - ip;
v2.x = ip + panel.clipSoftness.x;
if(panelTransfrom.localPosition.x == ip)
{
return;
}
}
else if(movement == UIScrollView.Movement.Vertical){
v3.y = ip - panel.clipSoftness.y;
v2.y = -ip + panel.clipSoftness.y;
if(panelTransfrom.localPosition.y == ip)
{
return;
}
} SpringPanel.Begin (sView.panel.cachedGameObject, v3, autoVelocity);
} /** 初始化 */
void initGrid()
{
ClearChild (); itemTrans = new Transform[defaultMaxLine];
for (int i = ; i < defaultMaxLine; i++) {
itemTrans[i] = CreatItemTransfrom(i);
} movement = sView.movement; sView.onDragStarted = onDragStarted;
sView.onDragFinished = onDragFinished;
sView.onMomentumMove = onMomentumMove;
sView.onStoppedMoving = onStoppedMoving; /** 初始化位置 */
ResetPostion (); /** 初始化数据 */
indexStar = ;
indexEnd = defaultMaxLine - ;
indexMax = ;
panelPos = Vector3.zero;
lastIndex = ;
showStartIndex = ;
if (scrollGridSetItem != null) {
scrollGridSetItem(itemTrans, indexStar, indexEnd);
}
SetMessage();
ResetScrollPanelPosition ();
} void ResetPostion()
{
float fristCoord = ;
bool hasFristCoord = false;
Vector3 np = Vector3.zero;
float vp = ;
float ip = ;
float fp = ;
if(movement == UIScrollView.Movement.Horizontal)
{
vp = vSize.x;
ip = size.x;
}else if(movement == UIScrollView.Movement.Vertical)
{
vp = vSize.y;
ip = size.y;
}
for(int i = ; i < itemTrans.Length; i++)
{
if(!hasFristCoord)
{
fristCoord = vp / 2.0f - ip / 2.0f;
if(fristCoord > vp / 2.0f)
{
fristCoord = vp / 2.0f;
}
hasFristCoord = true;
fp = fristCoord;
}else{
fp = fristCoord - (ip + space) * i;
}
if(movement == UIScrollView.Movement.Horizontal)
{
np.x = -fp;
}else if(movement == UIScrollView.Movement.Vertical)
{
np.y = fp;
}
itemTrans[i].localPosition = np;
}
}
#endregion #region switch Item
void SwitchItem(int id)
{
indexStar = id;
//Debug.Log("indexStar : " + indexStar.ToString());
if(movement == UIScrollView.Movement.Horizontal)
{
//Debug.Log("indexStar : " + indexStar.ToString());
//Debug.Log("stop : " + (indexMax - defaultMaxLine).ToString());
if(indexStar > )
{
indexStar = ;
return;
}
if(indexStar < -(indexMax - defaultMaxLine))
{
indexStar = indexMax - defaultMaxLine;
return;
}
indexStar = Mathf.Abs(indexStar);
}else if(movement == UIScrollView.Movement.Vertical)
{
/** star */
if(indexStar < )
{
indexStar = ;
return;
}
/**end*/
if(indexStar > indexMax - defaultMaxLine)
{
indexStar = indexMax - defaultMaxLine;
return;
}
} if (lastIndex != indexStar) {
if (lastIndex < indexStar) {
Transform t = itemTrans[];
for(int i = ; i < itemTrans.Length - ; i++)
{
itemTrans[i] = itemTrans[i+];
} float fy = ;
Vector3 v3 = t.localPosition;
if(movement == UIScrollView.Movement.Horizontal)
{
fy = itemTrans[itemTrans.Length - ].localPosition.x + size.x + space;
v3.x = fy;
}else if(movement == UIScrollView.Movement.Vertical)
{
fy = itemTrans[itemTrans.Length - ].localPosition.y - size.y - space;
v3.y = fy;
} t.localPosition = v3;
itemTrans[itemTrans.Length - ] = t;
}else{
Transform t = itemTrans[itemTrans.Length - ];
for(int i = itemTrans.Length - ; i > ; i--)
{
itemTrans[i] = itemTrans[i-];
} float fy = ;
Vector3 v3 = t.localPosition;
if(movement == UIScrollView.Movement.Horizontal)
{
fy = itemTrans[].localPosition.x - size.x - space;
v3.x = fy;
}else if(movement == UIScrollView.Movement.Vertical)
{
fy = itemTrans[].localPosition.y + size.y + space;
v3.y = fy;
} t.localPosition = v3;
itemTrans[] = t;
} lastIndex = indexStar; if (scrollGridSetItem != null) {
scrollGridSetItem(itemTrans, indexStar, indexEnd);
}
sView.UpdatePosition();
}
} /** 重置scroll panel */
void ResetScrollPanelPosition()
{
if(movement == UIScrollView.Movement.Horizontal)
{
if (indexStar == ) {
ResetPostion ();
Vector3 v3 = Vector3.zero;
v3.x = panel.clipSoftness.x;
Vector2 v2 = Vector2.zero;
v2.x = -panel.clipSoftness.x;
panelTransfrom.localPosition = v3;
panel.clipOffset = v2;
}
}
else if(movement == UIScrollView.Movement.Vertical){
if (indexStar == ) {
ResetPostion ();
Vector3 v3 = Vector3.zero;
v3.y = -panel.clipSoftness.y;
Vector2 v2 = Vector2.zero;
v2.y = panel.clipSoftness.y;
panelTransfrom.localPosition = v3;
panel.clipOffset = v2;
}
}
} void SetItemPostion(){
float fristCoord = GetPositionByIndex(indexStar);
//Debug.Log ("fristCoord = " + fristCoord + " indexStar " + indexStar);
Vector3 np = Vector3.zero;
float ip = ;
float fp = ;
if(movement == UIScrollView.Movement.Horizontal)
{
ip = size.x;
}else if(movement == UIScrollView.Movement.Vertical)
{
ip = size.y;
}
for(int i = ; i < itemTrans.Length; i++)
{
fp = fristCoord - (ip + space) * i;
if(movement == UIScrollView.Movement.Horizontal)
{
np.x = -fp;
}else if(movement == UIScrollView.Movement.Vertical)
{
np.y = fp;
}
itemTrans[i].localPosition = np;
}
} /** 通过index 获得item位置 */
public float GetPositionByIndex(int index)
{
float fristCoord = ;
bool hasFristCoord = false;
Vector3 np = Vector3.zero;
float vp = ;
float ip = ;
float fp = ;
if(movement == UIScrollView.Movement.Horizontal)
{
vp = vSize.x;
ip = size.x;
}else if(movement == UIScrollView.Movement.Vertical)
{
vp = vSize.y;
ip = size.y;
}
fristCoord = vp / 2.0f - ip / 2.0f;
if(fristCoord > vp / 2.0f)
{
fristCoord = vp / 2.0f;
} fp = fristCoord - (ip + space) * index;
return fp;
} /** 通过index 获得panel位置 */
public float GetPanelPositionByIndex(int index)
{
if(movement == UIScrollView.Movement.Horizontal)
{
return (size.x + space) * index;
}else if(movement == UIScrollView.Movement.Vertical)
{
return (size.y + space) * index;
}
return ;
} /** 获得列表显示的第一个的index */
int GetShowStartIndex()
{
Vector3 v3 = panelTransfrom.localPosition;
if(movement == UIScrollView.Movement.Horizontal)
{
if(indexStar > )
{
int index = (int)((v3.x - panel.clipSoftness.x) / (size.x + space));
return Mathf.Abs(index);
}
}else if(movement == UIScrollView.Movement.Vertical)
{
if(indexStar > )
{
int index = (int)((v3.y + panel.clipSoftness.y) / (size.y + space));
return index;
}
}
return indexStar;
}
#endregion #region 创建 和 清空Item
Transform CreatItemTransfrom(int index)
{
GameObject go = Instantiate (ItemPrefab, Vector3.zero, Quaternion.identity) as GameObject;
if (go != null) {
go.transform.parent = transform;
go.transform.localScale = Vector3.one;
go.transform.localPosition = Vector3.zero;
go.transform.localRotation = Quaternion.identity;
go.name = "ScrollGrid Item " + index.ToString(); return go.transform;
}
Debug.LogError ("scrollGrid creat item prefab ");
return null;
} public void ClearChild()
{
if (transform.childCount < ) {
return;
}
Transform t = transform.GetChild ();
t.parent = null;
Destroy (t.gameObject);
ClearChild ();
}
#endregion #region scroll delegate void onDragStarted()
{
//Debug.Log ("onDragStarted");
}
void onDragFinished()
{
//Debug.Log ("onDragFinished");
SetItemPostion();
if (centerScrollViewOnChild) {
GotoIndex(GetShowStartIndex());
}
} void onMomentumMove()
{
//Debug.Log ("onMomentumMove"); }
void onStoppedMoving()
{
//Debug.Log ("onStoppedMoving");
ResetScrollPanelPosition ();
}
#endregion #region update and LateUpdate
int stepIndex = ;
void LateUpdate (){
panelPos = panel.gameObject.transform.localPosition; if(movement == UIScrollView.Movement.Horizontal)
{
stepIndex = (int)(panelPos.x / (size.x + space));
}else if(movement == UIScrollView.Movement.Vertical)
{
stepIndex = (int)(panelPos.y / (size.y + space));
}
SwitchItem (stepIndex);
SetMessage();
}
#endregion #region message
/** 通知是否到两头 */
void SetMessage()
{
if (scrollGridMessage != null) {
int index = GetShowStartIndex();
if(index == )
{
if(indexMax <= defaultShowMaxLine)
{
scrollGridMessage();
}else{
scrollGridMessage(-);
}
}else{
if(indexMax - defaultShowMaxLine > index)
{
if(movement == UIScrollView.Movement.Horizontal)
{
if(index + == indexMax - defaultShowMaxLine)
{
if(Mathf.Abs(itemTrans[itemTrans.Length - ].localPosition.x) == Mathf.Abs(GetPositionByIndex(indexMax - )))
{
scrollGridMessage();
}else{
scrollGridMessage();
}
}else{
scrollGridMessage();
} }else if(movement == UIScrollView.Movement.Vertical)
{
if(index + == indexMax - defaultShowMaxLine)
{
if(Mathf.Abs(itemTrans[itemTrans.Length - ].localPosition.y) == Mathf.Abs(GetPositionByIndex(indexMax - )))
{
scrollGridMessage();
}else{
scrollGridMessage();
}
}else{
scrollGridMessage();
}
} }else{
scrollGridMessage();
}
}
}
}
#endregion
}
*********************************** 测试 **********************************
在unity里首先需要按照:
List为scrollView 的父类(空GameObject)

ScrollView为NGUI自带的组件
ScrollGrid为我们自己的脚本最后在用测试代码来测试
using UnityEngine;
using System.Collections; public class UITest : MonoBehaviour {
public ScrollGrid sg;
void Update()
{
if (Input.GetKeyDown (KeyCode.A)) {
sg.SetGrid(, setItem);
}
else if (Input.GetKeyDown (KeyCode.S)) {
sg.GotoIndex();
}
} void Start()
{
sg.SetGrid(, setItem);
}
void setItem(Transform[] t, int start, int end)
{
for (int i = ; i < t.Length; i++) {
t[i].GetComponent<ItemTest>().Name = "item " + (start + i).ToString();
}
}
}
******************** 测试结果 ******************************************************************************
希望我写的还算详细,就写到这里了!!!!!! 支持原创转载请注明出处http://home.cnblogs.com/u/fastHro/
NGUI ScrollView 循环 Item 实现性能优化的更多相关文章
- php 大数组 foreach 循环嵌套的性能优化
前提:最近在做后台的时候,页面加载太慢,故第一时间想到的自然是优化SQL, 优化后sql查询速度从 2秒变成了零点几秒, 以为就这麽完事了,然并卵,加载竟然花费30秒! 这麽慢,然后在代码中分块记录它 ...
- javascript循环---性能优化
循环是编程中是最为常见的结构,优化循环是性能优化中很重要的一个部分. 减值迭代:大多数循环使用一个从0开始.增加到某个特定值的迭代器.在很多情况下,从最大值开始,在循环中不断减值的迭代器更加高效. 简 ...
- 菜鸟要做架构师(二)——java性能优化之for循环
完成同样的功能,用不同的代码来实现,性能上可能会有比较大的差别,所以对于一些性能敏感的模块来说,对代码进行一定的优化还是很有必要的.今天就来说一下java代码优化的事情,今天主要聊一下对于for(wh ...
- for循环实战性能优化之使用Map集合优化
笔者在<for循环实战性能优化>中提出了五种提升for循环性能的优化策略,这次我们在其中嵌套循环优化小循环驱动大循环的基础上,借助Map集合高效的查询性能来优化嵌套for循环 ...
- JavaScript性能优化
如今主流浏览器都在比拼JavaScript引擎的执行速度,但最终都会达到一个理论极限,即无限接近编译后程序执行速度. 这种情况下决定程序速度的另一个重要因素就是代码本身. 在这里我们会分门别类的介绍J ...
- 【腾讯Bugly干货分享】跨平台 ListView 性能优化
本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/FbiSLPxFdGqJ00WgpJ94yw 导语 精 ...
- (转) Android开发性能优化简介
作者:贺小令 随着技术的发展,智能手机硬件配置越来越高,可是它和现在的PC相比,其运算能力,续航能力,存储空间等都还是受到很大的限制,同时用户对手机的体验要求远远高于PC的桌面应用程序.以上理由,足以 ...
- Android应用性能优化(转)
人类大脑与眼睛对一个画面的连贯性感知其实是有一个界限的,譬如我们看电影会觉得画面很自然连贯(帧率为24fps),用手机当然也需要感知屏幕操作的连贯性(尤其是动画过度),所以Android索性就把达到这 ...
- Android UI性能优化实战, 识别View中的性能问题
出自:[张鸿洋的博客]来源:http://blog.csdn.net/lmj623565791/article/details/45556391 1.概述 2015年初google发布了Android ...
随机推荐
- RTX2010服务器端的主要通信端口有哪些?
RTX服务端程序在安装之后,如果安装服务端电脑的操作系统有防火墙(如Windows XP.Windows2003等)或者安装了防火墙(如瑞星.Norton等),那么需要在防火墙上打开RTX所需要使用的 ...
- Practice:输入年月日,判断该时间为一年的第几天
#-*- coding:utf- -*- ''' Created on -- # 输入年月日,判断为一年的第几天 @author: AdministrInputator ''' def leapYea ...
- 验证码(网页的某些图片)在ie 360不显示,在火狐下显示正常
解决办法: 开始->运行,在运行输入框中输入“regsvr32 c:\windows\system32\pngfilt.dll”(不包含双引号),然后点击确定,如果在出现“已加载c:\windo ...
- 批量导入Excel存在的问题及解决方案
许多传统的做法,导入excel就是将excel上传到服务器的某个文件夹里如upload,之后再次读取,导入系统.这边就存在一些问题: 1.服务器需要安装Office,用于读取Excel文件. 2.系统 ...
- (Python )控制流语句if、for、while
这一节,我们将学习Python的控制流语句,主要包括if.for.while.break.continue 和pass语句 1. If语句 if语句也许是我们最熟悉的语句.其使用方法如下: x=inp ...
- 【Java学习笔记】<集合框架>定义功能去除ArrayList中的重复元素
import java.util.ArrayList; import java.util.Iterator; import cn.itcast.p1.bean.Person; public class ...
- [Chapter 3 Process]Practice 3.12 Including the initial parent process, how many processes are created by the program shown in Figure 3.32?
3.12 Including the initial parent process, how many processes are created by the program shown in Fi ...
- 使用Process类重定向输出与错误时遇到的问题 (转)
程序中要调用外部程序cmd.exe执行一些命令行,并取得屏幕输出,使用了Process类,基本代码如下: Process process = new Process(); process.StartI ...
- Orchard Oracle 支持
Orchard v1.7发布了,非常不错的一个升级,为了支持Oracle,基本上和v1.6版差不多,只是工作流相关的表有名字超长问题,改个名就可以了,作了个patch包,发布在: https://or ...
- SymmetricDS 3.5.0 发布,数据同步和复制
SymmetricDS 3.5.0 关闭 53 个问题,新增对 SQLite on Android.Sybase ASE 和 Sybase ASA 的支持:增加了文件同步功能,可同步目录.文件过滤和脚 ...

最后在用测试代码来测试
*******************************************************