目前只实现上下滑动
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using System;
using System.Linq;
public enum Direction
{
TopToBottom,//目前只实现
RightToLeft
}
public delegate void UpdateListItem(Transform item, int index, object data);
[RequireComponent(typeof(ScrollRect), typeof(RectMask2D))]
public class MyScrollList : MonoBehaviour
{
public GameObject itemPrefab;
public Direction dir = Direction.TopToBottom;
public int itemWidth; //单元格宽
public int itemHeight; //单元格高
public int rowCount;
public int colCount;
public int vGap = 0;//垂直间隔
public int hGap = 0;//水平间隔
public int paddingTop = 0;
public int paddingBottom = 0;
public int paddingLeft = 0;
public int paddingRight = 0;
private ScrollRect panel;
private object[] data;
private int startIndex;
private RectTransform content;
private UpdateListItem m_updateItem;
private Dictionary<int, Transform> itemDict = new Dictionary<int, Transform>();
public void OnEnable() //test
{
if (Application.isPlaying)
{
Init(new object[] { 0,1, 2, 3, 4, 5,6,7,8,9 }, delegate (Transform item, int index, object data)
{
item.Find("text").GetComponent<Text>().text = data.ToString();
});
}
}
// 初始化
public void Init(object[] dataList, UpdateListItem updateItem)
{
if (itemPrefab == null)
{
return;
}
data = dataList;
itemPrefab.SetActive(false);
m_updateItem = updateItem;
panel = GetComponent<ScrollRect>();
switch (dir)
{
case Direction.TopToBottom:
panel.vertical = true;
panel.horizontal = false;
break;
case Direction.RightToLeft:
panel.vertical = false;
panel.horizontal = true;
break;
}
if (content == null)
{
content = new GameObject("content").AddComponent<RectTransform>();
}
content.SetParent(transform);
content.pivot = new Vector2(0, 1);
content.anchorMax = content.anchorMin = new Vector2(0, 1);
int totalNum = Mathf.Max(dataList.Length, colCount * rowCount);
int totalRow = Mathf.CeilToInt(totalNum / colCount);
content.sizeDelta = new Vector2(colCount * (itemWidth) + (colCount - 1) * hGap + paddingLeft + paddingRight, totalRow * (itemHeight) + (totalRow - 1) * vGap + paddingBottom + paddingTop) ;
panel.content = content;
panel.onValueChanged.AddListener(OnScroll);
for (int i = 0; i < Mathf.Min(colCount * rowCount, dataList.Length) ; i++)
{
Transform item = UpdateItem(i);
itemDict[i] = item;
}
content.localScale = Vector3.one;
content.anchoredPosition = Vector2.zero;
}
private void OnScroll(Vector2 pos)
{
int rowIndex = (int)((content.anchoredPosition.y - paddingTop) / (itemHeight + vGap));
if (startIndex != rowIndex)
{
Dictionary<int, Transform> temp = new Dictionary<int, Transform>();
List<int> emptyIndex = new List<int>();
List<int> tempIndex = new List<int>();
for (int i = rowIndex; i < rowIndex + rowCount; i++)
{
for (int j = 0; j < colCount; j++)
{
int dataIndex = i * colCount + j;
if (itemDict.ContainsKey(dataIndex))
{
temp.Add(dataIndex, itemDict[dataIndex]);
itemDict.Remove(dataIndex);
}
else
{
//之前没有显示
emptyIndex.Add(dataIndex);
tempIndex.Add(dataIndex);
}
}
}
//上次显示,这次不用显示,优先把这些item用在这次显示上
foreach (var item in itemDict.Values)
{
var i = tempIndex[0];
tempIndex.RemoveAt(0);
temp[i] = item;
}
itemDict = temp;
//需要更新的
foreach (var i in emptyIndex)
{
UpdateItem(i);
}
startIndex = rowIndex;
}
}
// 创建item或者更新
private Transform UpdateItem(int index)
{
Transform item = null;
if (!itemDict.TryGetValue(index, out item))
{
item = GameObject.Instantiate(itemPrefab).transform;
var itemRect = item.GetComponent<RectTransform>();
itemRect.pivot = new Vector2(0, 1);
itemRect.anchorMax = itemRect.anchorMin = new Vector2(0, 1);
item.gameObject.SetActive(true);
item.SetParent(content);
item.localScale = Vector3.one;
item.name = index.ToString();
}
if (index<0 || index >= data.Length)
{
item.gameObject.SetActive(false);
return item;
}
// 1.行
int row = index / colCount;
// 2.列
int col = index % colCount;
item.GetComponent<RectTransform>().anchoredPosition = new Vector2(col * itemWidth + col * hGap + paddingLeft, -1 * row * itemHeight - row * vGap - paddingTop);
item.gameObject.SetActive(true);
if (m_updateItem != null)
{
m_updateItem(item, index, data[index]);
}
return item;
}
}
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
//预览工具
class GizmoList
{
[DrawGizmo(GizmoType.Selected | GizmoType.Active)]
private static void DrawGizmoForMyScrollList(MyScrollList grid, GizmoType gizmoType)
{
var gridRect = grid.GetComponent<RectTransform>();
var itemRect = new Rect(-grid.itemWidth / 2, -grid.itemHeight / 2, grid.itemWidth, grid.itemHeight);
int count = grid.rowCount * grid.colCount;
for (int i = 0; i < count; i++)
{
int row = i / grid.colCount;
int col = i % grid.colCount;
var offset = new Vector2(col * grid.itemWidth + col * grid.hGap - gridRect.rect.width /2f + 0.5f * grid.itemWidth + grid.paddingLeft, -1 * row * grid.itemHeight - row * grid.vGap + gridRect.rect.width / 2f - 0.5f * grid.itemHeight - grid.paddingTop);
DrawGizmoRect(gridRect, itemRect, offset, Color.red);
}
}
private static void DrawGizmoRect(RectTransform targetRect, Rect rect, Vector2 offset, Color color)
{
var lines = new List<Vector3>()
{
new Vector3(rect.xMin, rect.yMin, 0),
new Vector3(rect.xMin, rect.yMax, 0),
new Vector3(rect.xMax, rect.yMax, 0),
new Vector3(rect.xMax, rect.yMin, 0),
new Vector3(rect.xMin, rect.yMin, 0)
};
lines = lines.ConvertAll(a => (targetRect.TransformPoint(a + new Vector3(offset.x, offset.y, 0.0f))));
Handles.color = color;
Handles.DrawAAPolyLine(lines.ToArray());
}
}
演示