Unity UGUI Scroll View(滚动列表)优化
在游戏中很多UI设计都需要用到 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- 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
().rect.size.x; \\获取Item宽高
item_height = gameObj.transform.GetComponent().rect.height;
sv_width = scrollView.transform.GetComponent().rect.size.x; \\获取scroll view 宽高
sv_height = scrollView.transform.GetComponent().rect.height;
HorizontalScrollBar.transform.GetComponent().sizeDelta = new Vector2(sv_width ,30); //设置scroll bar坐标
HorizontalScrollBar.transform.localPosition = new Vector3(0, -sv_height, 0) + scrollView.transform.localPosition;
VerticalScrollBar.transform.GetComponent().sizeDelta = new Vector2(30, sv_height);
VerticalScrollBar.transform.localPosition = new Vector3(sv_width, 0, 0) + scrollView.transform.localPosition;
itemList = new List- ();
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
().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().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().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;
}
}