今天来说说一直都让我在项目中头疼的其中一个问题,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 实现性能优化的更多相关文章

  1. php 大数组 foreach 循环嵌套的性能优化

    前提:最近在做后台的时候,页面加载太慢,故第一时间想到的自然是优化SQL, 优化后sql查询速度从 2秒变成了零点几秒, 以为就这麽完事了,然并卵,加载竟然花费30秒! 这麽慢,然后在代码中分块记录它 ...

  2. javascript循环---性能优化

    循环是编程中是最为常见的结构,优化循环是性能优化中很重要的一个部分. 减值迭代:大多数循环使用一个从0开始.增加到某个特定值的迭代器.在很多情况下,从最大值开始,在循环中不断减值的迭代器更加高效. 简 ...

  3. 菜鸟要做架构师(二)——java性能优化之for循环

    完成同样的功能,用不同的代码来实现,性能上可能会有比较大的差别,所以对于一些性能敏感的模块来说,对代码进行一定的优化还是很有必要的.今天就来说一下java代码优化的事情,今天主要聊一下对于for(wh ...

  4. for循环实战性能优化之使用Map集合优化

           笔者在<for循环实战性能优化>中提出了五种提升for循环性能的优化策略,这次我们在其中嵌套循环优化小循环驱动大循环的基础上,借助Map集合高效的查询性能来优化嵌套for循环 ...

  5. JavaScript性能优化

    如今主流浏览器都在比拼JavaScript引擎的执行速度,但最终都会达到一个理论极限,即无限接近编译后程序执行速度. 这种情况下决定程序速度的另一个重要因素就是代码本身. 在这里我们会分门别类的介绍J ...

  6. 【腾讯Bugly干货分享】跨平台 ListView 性能优化

    本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/FbiSLPxFdGqJ00WgpJ94yw 导语 精 ...

  7. (转) Android开发性能优化简介

    作者:贺小令 随着技术的发展,智能手机硬件配置越来越高,可是它和现在的PC相比,其运算能力,续航能力,存储空间等都还是受到很大的限制,同时用户对手机的体验要求远远高于PC的桌面应用程序.以上理由,足以 ...

  8. Android应用性能优化(转)

    人类大脑与眼睛对一个画面的连贯性感知其实是有一个界限的,譬如我们看电影会觉得画面很自然连贯(帧率为24fps),用手机当然也需要感知屏幕操作的连贯性(尤其是动画过度),所以Android索性就把达到这 ...

  9. Android UI性能优化实战, 识别View中的性能问题

    出自:[张鸿洋的博客]来源:http://blog.csdn.net/lmj623565791/article/details/45556391 1.概述 2015年初google发布了Android ...

随机推荐

  1. ABAP BDC

    REPORT程序中用BDC录入 DATA: GS_BDC TYPE BDCDATA, GT_BDC TYPE TABLE OF BDCDATA, GS_MSG TYPE BDCMSGCOLL, GT_ ...

  2. [转载] 散列表(Hash Table)从理论到实用(上)

    转载自:白话算法(6) 散列表(Hash Table)从理论到实用(上) 处理实际问题的一般数学方法是,首先提炼出问题的本质元素,然后把它看作一个比现实无限宽广的可能性系统,这个系统中的实质关系可以通 ...

  3. php 获取代码执行时间和消耗的内存

    做一些php性能测试的时候,要获取代码执行时间和消耗的内存,查了一下资料,发现php有自带的函数可以实现这个功能,具体实现代码如下: $t1 = microtime(true);// ... 执行代码 ...

  4. JS实现滑动门效果

    html部分 p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 31.0px Consolas; color: #2b7ec3 } p.p2 { margin ...

  5. 关于CSS3的代码总结(部分)

    1. 构造样式表:selector{ Property:value; Property:value; } Selector是需要更改样式的元素,property为css属性的名称,value应用的哪种 ...

  6. [SmartFoxServer概述]SFS2X栈平台

    SmartFoxServer 2X 栈平台 在这有一张SmartFoxServer 2X平台的鸟瞰图,接下来会简要介绍栈中的每个组件. 首先是服务器的核心——网络引擎(代号BitSwarm),它是用以 ...

  7. 5.1 Intent

    Intent是不同组件之间相互通讯的纽带,封装了不同组件之间通讯的条件.Intent用于启动Activity, Service, 以及BroadcastReceiver三种组件, 同时还是组件之间通信 ...

  8. sql命令查看,清楚mysql bin日志

    查看二进制日志文件 mysql> SHOW BINLOG EVENTS \G; mysql> SHOW MASTER LOGS; 清除二进制日志文件 mysql> PURGE { M ...

  9. 一个通用的makefile

    # ESDK the makefile setting file - chenwg@20131014 # you can modify "PC = 1" such as " ...

  10. Spring <context:annotation-config/> 解说

    在基于主机方式配置Spring的配置文件中,你可能会见到<context:annotation-config/>这样一条配置,他的作用是式地向 Spring 容器注册 AutowiredA ...