Unity UGUI Scroll View(滚动列表)优化

发表于2018-10-29
评论1 8.4k浏览
在游戏中很多UI设计都需要用到 Scroll View 控件,如排行榜、聊天室、背包等。当需要显示的物品达到千量级以上的时候,就会造成大量内存上的占用,列表滚动的时候也会触发大量的计算,会照成卡顿。接下来讲讲如何对Scroll View做优化。


注意看Hierarchy中UIgrid下始终只有4个Item

优化策略就是只创建屏幕能放下的item的数量再加一个的item。当列表滚动时利用再外面不显示出来的item进行设置坐标即可。

方法还是不难的,所以我们直接看代码,注释只写出了grid上移时的情况,其余同理。
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using System.Collections;
using System.Collections.Generic;
using System;
public class ScrollViewManager : MonoBehaviour
{
    public enum style {
        Horizontal,                         //横向分布
        Vertical,                           //纵向分布
        //HorizontalAndVertical               //横向和纵向分布
    };
    public Image scrollView;                //scroll view  
    public Image grid;                      //grid
    public Scrollbar HorizontalScrollBar;   //控制horizontal的scroll bar
    public Scrollbar VerticalScrollBar;     //控制vertical的scroll bar
    public int number;                      //物品总数量
    public float middle;                    //物品间距
    public style manage_style;              //管理物品方式
    //public int rowCount;                    //行数
    //public int columnCount;                 //列数
    public string prefab_path;              //物品资源路径
    private List<Item> itemList;            //存放物品的列表
    private float item_width;               //物品宽度
    private float item_height;              //物品高度
    private float sv_width;                 //scroll view宽度
    private float sv_height;                //scroll view高度   
    private float grid_width;               //grid宽度
    private float grid_height;              //grid高度
    private int row;                        //grid内可放物品行数
    private int column;                     //grid内可放物品列数
    private GameObject gameObj;             //物品对象
    private GameObject obj;                 //实例化物品对象
    private Vector3 gridOldPosition;        //grid更新前的坐标
    // Use this for initialization
    void Start()
    {
        gameObj = Resources.Load(prefab_path) as GameObject;   \\加载prefab
        grid.transform.localPosition = new Vector3(0, 0, 0);   \\设置grid坐标
        item_width = gameObj.transform.GetComponent<RectTransform>().rect.size.x;  \\获取Item宽高
        item_height = gameObj.transform.GetComponent<RectTransform>().rect.height;
        sv_width = scrollView.transform.GetComponent<RectTransform>().rect.size.x;  \\获取scroll view 宽高
        sv_height = scrollView.transform.GetComponent<RectTransform>().rect.height;
        HorizontalScrollBar.transform.GetComponent<RectTransform>().sizeDelta = new Vector2(sv_width ,30);    //设置scroll bar坐标
        HorizontalScrollBar.transform.localPosition = new Vector3(0, -sv_height, 0) + scrollView.transform.localPosition;
        VerticalScrollBar.transform.GetComponent<RectTransform>().sizeDelta = new Vector2(30, sv_height);
        VerticalScrollBar.transform.localPosition = new Vector3(sv_width, 0, 0) + scrollView.transform.localPosition;
        itemList = new List<Item>();
        switch (manage_style)  //根据所选排列方式初始化创建Item
        {
            case style.Horizontal:
                grid_width = number * (middle + item_width);
                column = GetUpInt(sv_width, item_width + middle) + 1;
                if (grid_width <= sv_width)
                {
                    column = number;
                    grid_width = sv_width;
                }
                grid_height = sv_height;
                row = 1;
                grid.transform.GetComponent<RectTransform>().sizeDelta = new Vector2(grid_width, grid_height);   
                HorizontalInitItem();
                break;
            case style.Vertical:
                grid_width = sv_width;
                column = 1;
                grid_height = number * (middle + item_height);
                row = GetUpInt(sv_height, item_height + middle) + 1;
                if (grid_height <= sv_height)
                {
                    row = number;
                    grid_height = sv_height;
                }
                grid.transform.GetComponent<RectTransform>().sizeDelta = new Vector2(grid_width, grid_height);
                VerticalInitItem();
                break;
            //case style.HorizontalAndVertical:   //既上下滑动又左右滑动的有些问题先注释掉
            //    grid_width = columnCount * (middle + item_width);
            //    column = (int)(sv_width / (item_width + middle)) + 1;
            //    if (grid_width <= sv_width)
            //    {
            //        column = columnCount;
            //        grid_width = sv_width;                   
            //    }
            //    grid_height = rowCount * (middle + item_height);
            //    row = (int)(sv_height / (item_height + middle)) + 1;
            //    if (grid_height <= sv_height)
            //    {
            //        row = rowCount;
            //        grid_height = sv_height;
            //    }
            //    grid.transform.GetComponent<RectTransform>().sizeDelta = new Vector2(grid_width, grid_height);
            //    HorizontalAndVerticalInitItem();
            //    break;
        }
    }
    void HorizontalInitItem() {
        for (int i = 0; i < column; i++) {
            obj = Instantiate(gameObj);
            obj.transform.SetParent(grid.transform);
            obj.transform.localPosition = new Vector3(middle / 2 + item_width / 2 + (middle + item_width) * i, -(sv_height / 2), 0);
            Item item = new Item();
            item.BindGameObject(obj);
            item.SetData(i + 1);
            itemList.Add(item);
        }
    }
    void VerticalInitItem() {
        for (int i = 0; i < row; i++){
            obj = Instantiate(gameObj);
            obj.transform.SetParent(grid.transform);
            obj.transform.localPosition = new Vector3(sv_width / 2, -(middle / 2 + item_height / 2 + (middle + item_height) * i), 0);
            Item item = new Item();
            item.BindGameObject(obj);
            item.SetData(i + 1);
            itemList.Add(item);
        }
    }
    //void HorizontalAndVerticalInitItem() {
    //    for (int i = 0; i < row; i++) {
    //        for (int j = 0; j < column; j++) {
    //            obj = Instantiate(gameObj);
    //            obj.transform.SetParent(grid.transform);
    //            obj.transform.localPosition = new Vector3(middle / 2 + item_width / 2 + (middle + item_width) * j, -(middle / 2 + item_height / 2 + (middle + item_height) * i), 0);
    //            Item item = new Item();
    //            item.BindGameObject(obj);
    //            item.SetData(i * columnCount + j + 1);
    //            itemList.Add(item);
    //        }
    //    }
    //}
    // Update is called once per frame
    //根据grid的移动调整Item的位置
    void Update()
    {
        Vector3 gridNewPosition = grid.transform.localPosition;
        float h = gridNewPosition.y - gridOldPosition.y;
        float w = gridNewPosition.x - gridOldPosition.x;
        gridOldPosition = grid.transform.localPosition;
        if (h > 0.05f)
        {   \\当最后一个Item的值小于总量
            if (itemList[row - 1].GetData() < number)
            {   \\当第一个Item的位置已经超出了一gird上一个Item的距离
                while (itemList[0].GetGameObjectPosition().y + gridNewPosition.y > (item_height + middle) / 2)
                {
                    Up();    //调整第一个Item位置
                }
            }
        }
        else if (h < -0.05f)
        {
            if (itemList[0].GetData() > 1)
            {
                while (itemList[row - 1].GetGameObjectPosition().y + gridNewPosition.y < -(sv_height + (item_height + middle) / 2))
                {
                    Down();
                }
            }
        }
        if (w > 0.05f)
        {
            if (itemList[0].GetData() > 1)
            {
                while (itemList[column - 1].GetGameObjectPosition().x + gridNewPosition.x > (sv_width + (item_width + middle) / 2))
                {
                    Right();
                }
            }
        }
        else if (w < -0.05f)
        {
            if (itemList[column - 1].GetData() < number)
            {
                while (itemList[0].GetGameObjectPosition().x + gridNewPosition.x < -((item_width + middle) / 2))
                {
                    Left();
                }
            }
        }
    }
    void Up(){
            //将第一个Item的位置放到最后一个Itemd的下方
        itemList[0].SetGameObjectPosition(itemList[row - 1].GetGameObjectPosition() + new Vector3(0, -(item_height + middle), 0));
        itemList[0].SetData(itemList[row - 1].GetData() + 1);
        itemList.Add(itemList[0]);
        itemList.RemoveAt(0);
    }
    void Down() {
        itemList[row - 1].SetGameObjectPosition(itemList[0].GetGameObjectPosition() + new Vector3(0, item_height + middle, 0));
        itemList[row - 1].SetData(itemList[0].GetData() - 1);
        itemList.Insert(0, itemList[row - 1]);
        itemList.RemoveAt(row);
    }
    void Left(){
        itemList[0].SetGameObjectPosition(itemList[column - 1].GetGameObjectPosition() + new Vector3(item_width + middle, 0, 0));
        itemList[0].SetData(itemList[column - 1].GetData() + 1);
        itemList.Add(itemList[0]);
        itemList.RemoveAt(0);
    }
    void Right() {
        itemList[column - 1].SetGameObjectPosition(itemList[0].GetGameObjectPosition() + new Vector3(-(item_width + middle), 0, 0));
        itemList[column - 1].SetData(itemList[0].GetData() - 1);
        itemList.Insert(0, itemList[column - 1]);
        itemList.RemoveAt(column);
    }
    int GetUpInt(float a, float b) {
        int i = 0;
        while (a > 0) {
            a -= b;
            i++;
        }
        return i;
    } 
}

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引