Unity UGUI Scroll View(滚动列表)优化
发表于2018-10-29
在游戏中很多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; } }