今天來講說一直都讓我在項目中頭疼的其中一個問題,NGUI 的scrollView 列表性能問題,實現循環使用item減小性能上的開銷。ide
但願可以給其餘同窗們使用和提供一個我我的的思路,這個寫的不是太完美,目前我在項目中使用了,但願大神可以給更多的建議來優化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 = 0; private int indexEnd = 0; private int indexMax = 0; private Vector3 panelPos = Vector3.zero; private int lastIndex = 0; private int showStartIndex = 0; #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 + 1); } /** 向前滑動一格 */ public void PreIndex() { int ix = GetShowStartIndex (); //Debug.Log ("pre = " + ix); GotoIndex (ix - 1); } /**直接跳到指定位置*/ public void GotoIndex(int index) { if (index < 0) { 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 = 0; i < defaultMaxLine; i++) { itemTrans[i] = CreatItemTransfrom(i); } movement = sView.movement; sView.onDragStarted = onDragStarted; sView.onDragFinished = onDragFinished; sView.onMomentumMove = onMomentumMove; sView.onStoppedMoving = onStoppedMoving; /** 初始化位置 */ ResetPostion (); /** 初始化數據 */ indexStar = 0; indexEnd = defaultMaxLine - 1; indexMax = 0; panelPos = Vector3.zero; lastIndex = 0; showStartIndex = 0; if (scrollGridSetItem != null) { scrollGridSetItem(itemTrans, indexStar, indexEnd); } SetMessage(); ResetScrollPanelPosition (); } void ResetPostion() { float fristCoord = 0; bool hasFristCoord = false; Vector3 np = Vector3.zero; float vp = 0; float ip = 0; float fp = 0; 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 = 0; 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 > 0) { indexStar = 0; return; } if(indexStar < -(indexMax - defaultMaxLine)) { indexStar = indexMax - defaultMaxLine; return; } indexStar = Mathf.Abs(indexStar); }else if(movement == UIScrollView.Movement.Vertical) { /** star */ if(indexStar < 0) { indexStar = 0; return; } /**end*/ if(indexStar > indexMax - defaultMaxLine) { indexStar = indexMax - defaultMaxLine; return; } } if (lastIndex != indexStar) { if (lastIndex < indexStar) { Transform t = itemTrans[0]; for(int i = 0; i < itemTrans.Length - 1; i++) { itemTrans[i] = itemTrans[i+1]; } float fy = 0; Vector3 v3 = t.localPosition; if(movement == UIScrollView.Movement.Horizontal) { fy = itemTrans[itemTrans.Length - 2].localPosition.x + size.x + space; v3.x = fy; }else if(movement == UIScrollView.Movement.Vertical) { fy = itemTrans[itemTrans.Length - 2].localPosition.y - size.y - space; v3.y = fy; } t.localPosition = v3; itemTrans[itemTrans.Length - 1] = t; }else{ Transform t = itemTrans[itemTrans.Length - 1]; for(int i = itemTrans.Length - 1; i > 0; i--) { itemTrans[i] = itemTrans[i-1]; } float fy = 0; Vector3 v3 = t.localPosition; if(movement == UIScrollView.Movement.Horizontal) { fy = itemTrans[1].localPosition.x - size.x - space; v3.x = fy; }else if(movement == UIScrollView.Movement.Vertical) { fy = itemTrans[1].localPosition.y + size.y + space; v3.y = fy; } t.localPosition = v3; itemTrans[0] = t; } lastIndex = indexStar; if (scrollGridSetItem != null) { scrollGridSetItem(itemTrans, indexStar, indexEnd); } sView.UpdatePosition(); } } /** 重置scroll panel */ void ResetScrollPanelPosition() { if(movement == UIScrollView.Movement.Horizontal) { if (indexStar == 0) { 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 == 0) { 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 = 0; float fp = 0; if(movement == UIScrollView.Movement.Horizontal) { ip = size.x; }else if(movement == UIScrollView.Movement.Vertical) { ip = size.y; } for(int i = 0; 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 = 0; bool hasFristCoord = false; Vector3 np = Vector3.zero; float vp = 0; float ip = 0; float fp = 0; 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 0; } /** 得到列表顯示的第一個的index */ int GetShowStartIndex() { Vector3 v3 = panelTransfrom.localPosition; if(movement == UIScrollView.Movement.Horizontal) { if(indexStar > 0) { int index = (int)((v3.x - panel.clipSoftness.x) / (size.x + space)); return Mathf.Abs(index); } }else if(movement == UIScrollView.Movement.Vertical) { if(indexStar > 0) { 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 < 1) { return; } Transform t = transform.GetChild (0); 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 = 0; 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 == 0) { if(indexMax <= defaultShowMaxLine) { scrollGridMessage(0); }else{ scrollGridMessage(-1); } }else{ if(indexMax - defaultShowMaxLine > index) { if(movement == UIScrollView.Movement.Horizontal) { if(index + 1 == indexMax - defaultShowMaxLine) { if(Mathf.Abs(itemTrans[itemTrans.Length - 1].localPosition.x) == Mathf.Abs(GetPositionByIndex(indexMax - 1))) { scrollGridMessage(1); }else{ scrollGridMessage(2); } }else{ scrollGridMessage(2); } }else if(movement == UIScrollView.Movement.Vertical) { if(index + 1 == indexMax - defaultShowMaxLine) { if(Mathf.Abs(itemTrans[itemTrans.Length - 1].localPosition.y) == Mathf.Abs(GetPositionByIndex(indexMax - 1))) { scrollGridMessage(1); }else{ scrollGridMessage(2); } }else{ scrollGridMessage(2); } } }else{ scrollGridMessage(1); } } } } #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(20, setItem); } else if (Input.GetKeyDown (KeyCode.S)) { sg.GotoIndex(5); } } void Start() { sg.SetGrid(20, setItem); } void setItem(Transform[] t, int start, int end) { for (int i = 0; i < t.Length; i++) { t[i].GetComponent<ItemTest>().Name = "item " + (start + i).ToString(); } } }
******************** 測試結果 ***********************

*******************************************************
但願我寫的還算詳細,就寫到這裏了!!!!!!
支持原創轉載請註明出處http://home.cnblogs.com/u/fastHro/