zoukankan      html  css  js  c++  java
  • 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 = 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/
     
    
    
    
     
  • 相关阅读:
    MySQL表行数查询最佳实践
    mysqldump备份表中有大字段失败的排错过程
    μC/OSⅡ在C8051F060上的移植及其应用
    OSSchedLock()函数透析
    32位与64位区别
    【Cesium】Animation显示系统时间
    【Cesium】根据经纬度计算距离
    【Cesium】 鼠标拾取椭球、地形、模型坐标点(经度+纬度+高程)
    【Python学习】Selenium模拟浏览器抓取数据
    【Cesium】polygon中的height和extrudedHeight的区别
  • 原文地址:https://www.cnblogs.com/fastHro/p/4381725.html
Copyright © 2011-2022 走看看