两个脚本,分别放在ScrollView和content下的item上
UIScroll
利用content的位置来计算item的index,用ScrollRect.onValueChanged.AddListener(action)来监听滑动,然后进行相关计算。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UIScroll : MonoBehaviour
{
public enum Direction
{
Horizontal,
Vertical,
}
public Direction direction;
public Vector2 cellSize;
public Vector2 spacing;
private Action<UIScrolItem, int> updateAction;
private RectTransform rectTransform;
private ScrollRect scrollRect;
private RectTransform content;
private float contentWidth;
private float contentHeight;
private Vector2 contentOriginalSize;
private float itemWidth;
private float itemHeight;
private int columnCount;
private int rowCount;
private int createCount;
private int listCount;
private int showCount;
private int columnSum;
private int rowSum;
private int startIndex = 0;
private int endIndex = 0;
private int lastStartIndex=0;
private Dictionary<int, Transform> itemIndexDict = new Dictionary<int, Transform>();
private void Awake()
{
rectTransform = GetComponent<RectTransform>();
scrollRect = GetComponent<ScrollRect>();
content = transform.Find("Viewport/Content").GetComponent<RectTransform>();
contentOriginalSize = content.sizeDelta;
}
private void OnEnable()
{
scrollRect.onValueChanged.AddListener(OnValueChanged);
}
public void init(int count)
{
startIndex = endIndex = lastStartIndex = 0;
itemWidth = cellSize.x;
itemHeight = cellSize.y;
if (columnCount <= 0)
columnCount = (int)(contentOriginalSize.x / (itemWidth+spacing.x));
if (rowCount <= 0)
rowCount = (int)(contentOriginalSize.y / (itemHeight+spacing .y));
InitData();
InitList(count);
}
private void InitData()
{
if(direction==Direction.Horizontal)
{
scrollRect.horizontal = true;
scrollRect.vertical = false;
}
else
{
scrollRect.horizontal = false;
scrollRect.vertical = true;
}
foreach (Transform item in content.transform)
{
UIScrolItem cell = item.GetComponent<UIScrolItem>();
if (cell.GetItem() != null)
{
}
cell.SetItem(null);
}
content.pivot =
content.anchorMin =
content.anchorMax = new Vector2(0, 1);
content.sizeDelta = contentOriginalSize;
content.anchoredPosition = Vector2.zero;
columnCount = (int)(contentOriginalSize.x / (itemWidth + spacing.x));
rowCount = (int)(contentOriginalSize.y / (itemHeight + spacing.y));
int c = columnCount;
int r = rowCount;
if (direction == Direction.Horizontal)
c += 2;
else r += 2;
createCount = c * r;
}
private void InitList(int count)
{
listCount = count;
content.transform.localPosition = Vector2.zero;
if(direction == Direction.Horizontal)
{
columnSum = count / rowCount + count % rowCount == 0 ? 0 : 1;
contentWidth = columnSum * itemWidth + (columnSum - 1) * spacing.x;
contentHeight = rowCount * itemHeight + (rowCount - 1) * spacing.y;
}
else
{
rowSum = (count / columnCount) + (count % columnCount == 0 ? 0 : 1);
contentWidth = columnCount * itemWidth + (columnCount - 1) * spacing.x;
contentHeight = rowSum * itemHeight + (rowSum - 1) * spacing.y;
}
content.sizeDelta = new Vector2(contentWidth, contentHeight);
startIndex = 0;
showCount = Math.Min(createCount, count);
itemIndexDict.Clear();
for(int i=0;i<showCount;i++)
{
Transform item = GetItem(i);
SetItem(item,i);
}
}
public Transform GetItem(int index)
{
Transform item = null;
if(index<content.childCount)
{
item = content.GetChild(index);
}
else
{
var go = new GameObject(index.ToString(), typeof(UIScrolItem));
var uiScrollItem = go.GetComponent<UIScrolItem>();
uiScrollItem.init(itemWidth, itemHeight);
go.transform.SetParent(content);
item = go.transform;
}
item.name = index.ToString();
item.SetParent(content);
item.localPosition = Vector3.one;
return item;
}
public void SetItem(Transform item,int index)
{
item.localPosition = GetPos(index);
item.name = index.ToString();
item.SetParent(content);
itemIndexDict.Add(index, item);
Debug.Log("向itemIndexDict中添加" + index.ToString());
}
public Vector2 GetPos(int index)
{
if (direction == Direction.Horizontal)
return GetPosH(index);
else return GetPosV(index);
}
public Vector2 GetPosH(int index)
{
Vector2 v = new Vector2(index / rowCount * (itemWidth + spacing.x), ((((index + 1) % rowCount) == 0 ? rowCount : ((index + 1) % rowCount)) - 1) * (itemHeight + spacing.y));
return v;
}
public Vector2 GetPosV(int index)
{
Vector2 v = new Vector2(((((index + 1) % columnCount) == 0 ? columnCount : ((index + 1) % columnCount))-1) * (itemWidth + spacing.x), -index / columnCount * (itemHeight + spacing.y));
return v;
}
private List<int> newIndexList = new List<int>();
private List<int> changedIndexList = new List<int>();
Vector2 _pos;
public void OnValueChanged(Vector2 pos)
{
_pos = pos;
if (listCount < createCount)
return;
startIndex = GetStartIndex(content.localPosition);
if (startIndex + createCount > listCount)
{
startIndex = listCount - createCount;
endIndex = listCount - 1;
}
else endIndex = startIndex + createCount - 1;
if (startIndex == lastStartIndex)
return;
lastStartIndex = startIndex;
newIndexList.Clear();
changedIndexList.Clear();
for(int i=startIndex;i<=endIndex;i++)
{
newIndexList.Add(i);
Debug.Log("向newIndexList中添加" + i);
}
var itr = itemIndexDict.GetEnumerator();
while(itr.MoveNext())
{
int idx = itr.Current.Key;
if(idx>=startIndex && idx<=endIndex)
{
if (newIndexList.Contains(idx))
{
newIndexList.Remove(idx);
Debug.Log("从newIndexList中删除" + idx);
}
continue;
}
else
{
changedIndexList.Add(idx);
}
}
for(int i=0;i<newIndexList.Count && i<changedIndexList.Count;i++)
{
int newIndex = newIndexList[i];
int oldIndex = changedIndexList[i];
if(newIndex >= 0 && newIndex < listCount)
{
var item = itemIndexDict[oldIndex];
itemIndexDict.Remove(oldIndex);
SetItem(item, newIndex);
}
}
}
public int GetStartIndex(Vector2 v)
{
if (direction == Direction.Horizontal)
return GetStartIndexH(v.x);
else
return GetStartIndexV(v.y);
}
public int GetStartIndexH(float x)
{
x = -x;
if (x < itemWidth)
return 0;
float scrollWidth = rectTransform.sizeDelta.x;
if(x>(content.sizeDelta.x - scrollWidth))
{
if (listCount < createCount)
return 0;
else
return listCount - createCount;
}
return (int)(x / (itemWidth + spacing.x)) * rowCount + ((x % (itemWidth + spacing.x)) > 0 ? 1 : 0) - 1;
}
public int GetStartIndexV(float y)
{
if (y < itemHeight)
return 0;
float scrollHeight = rectTransform.sizeDelta.y;
if(y>(content.sizeDelta.y - scrollHeight))
{
if (listCount < createCount)
return 0;
else
return listCount - createCount;
}
return (int)(y / (itemHeight + spacing.y)) * columnCount + ((y % (itemHeight + spacing.y)) > 0 ? 1 : 0 )-1;
}
}
UIScrolItem
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(RectTransform),typeof(Image))]
public class UIScrolItem : MonoBehaviour
{
private RectTransform rectTransform;
private RectTransform item;
private void Awake()
{
rectTransform = GetComponent<RectTransform>();
}
public void init(float w,float h)
{
rectTransform.pivot =
rectTransform.anchorMin =
rectTransform.anchorMax = new Vector2(0, 1);
rectTransform.sizeDelta = new Vector2(w, h);
}
public void SetItem(RectTransform rt)
{
if(rt!=item)
{
if(rt!=null)
{
rt.SetParent(transform);
rt.localPosition = Vector2.one;
}
item = rt;
}
}
public RectTransform GetItem()
{
return item;
}
}
在随便一个按钮上添加一个事件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MainUi : MonoBehaviour
{
public Button[] buttons=new Button[3];
public GameObject scrollView;
public UIScroll uIScroll;
public void OnClickBag()
{
if(!scrollView.activeInHierarchy)
{
scrollView.SetActive(true);
uIScroll.init(100);
}
else
{
scrollView.SetActive(false);
}
}
}