今天来说说一直都让我在项目中头疼的其中一个问题,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. Android广播错误.MainActivity$MyReceiver; no empty constructor

    广播的定义,如果是内部类,必须为静态类. 下面总结一下作为内部类的广播接收者在注册的时候需要注意的地方:   1.清单文件注册广播接收者时,广播接收者的名字格式需要注意.因为是内部类,所以需要在内部类 ...

  2. STS 代码提示快捷键 和 注解提示的修改

    window->Preferences window->Preferences

  3. hdu 5818 (优先队列) Joint Stacks

    题目:这里 题意: 两个类似于栈的列表,栈a和栈b,n个操作,push a x表示把数x放进a栈的栈底,pop b 表示将栈b的栈顶元素取出输出,并释放这个栈顶元素,merge a b表示把后面的那个 ...

  4. 完全背包问题 POJ1384

    完全背包即物品的数量不收限制, 根据01背包的思想,因为每件物品只能选1个,则要求我们不能依赖已选择物品i的选项的时候,所以需要逆序遍历 则在完全背包问题中,我们需要正序遍历. 此题时要求求出最小价值 ...

  5. 关于php中正则匹配包括换行符在内的任意字符的问题总结

    要使用正则匹配任意字符的话,通常有以下几种方法,这里我分别对每一种方法在使用的过程中做一个总结: 第一种方式:[.\n]*? 示例 ? PHP preg_match_all('/<div cla ...

  6. Android NDK构建资料

    Cmake http://blog.csdn.net/u012527560/article/details/51752070  http://wenku.baidu.com/link?url=ENJF ...

  7. VB6.0 调用存储过程

    最近有在做一个需求,需要在VB6.0中调用存储过程,整理了一下,供大家参考, 范例: Function callStoredProcedure(sEmployeeID As String, Optio ...

  8. XMl入门介绍及php操作XML

    一.什么是XML XML全称:Extensible Markup Language 中文名:可扩展标记语言 用于标记电子文件使其具有结构性的标记语言,可以用来标记数据,定义数据类型,允许用户对自己的标 ...

  9. lvs主备可以自由切换,vip落在主上的时候,端口无法telnet,业务连接不了

    lvs主备可以自由切换,vip落在主上的时候,端口无法telnet,业务连接不了 解决:将主上的keepalived重启,故障解除 原因:不可知 lvs常见故障原因: real server上的脚步没 ...

  10. Replace Pioneer 续用2

    软件介绍(摘自百度百科) Replace Pioneer(中文名:替换先锋)是Mind Pioneer出品的一款共享软件.    Replace Pioneer是一款与众不同的专业文本批量替换和处理软 ...