参考网上很多的代码修改的
上代码
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
[DisallowMultipleComponent]
[RequireComponent(typeof(ScrollRect))]
//Content 上不用加任何组件
public class SuperScrollView : MonoBehaviour
{
public int space;//间距
public GameObject itemPrefab;//预制
public string nameHead = "";
private enum ScrollRect_Direction : byte
{
Horizontal,
Vertical
}
private ScrollRect_Direction m_Direction = ScrollRect_Direction.Horizontal; //拖动方向.
private float itemHeight;//item的高度(全都一样)
private float itemWidth;
private ScrollRect mScrollRect;
private RectTransform mContentRect;
private Action<GameObject, int> itemUpdateCallBack;
private List<GameObject> gameObjectList;
private int datasNum;//当前数据数量
//记录最上和最下的item索引
private int firstIndex;
private int lastIndex;
public List<GameObject> itemList;
private int needItemNum = 0;
private int calItemNum = 0;
private bool ready = false;
private bool inited = false;
private int reqItemNum = 2;
private void Awake()
{
if (!inited) Init();
}
private void Init()
{
itemList = new List<GameObject>();
gameObjectList = new List<GameObject>();
mScrollRect = transform.GetComponent<ScrollRect>();
mContentRect = mScrollRect.content.transform.GetComponent<RectTransform>();
mScrollRect.onValueChanged.AddListener((Vector2 vec) => OnScrollMove(vec));
itemHeight = itemPrefab.GetComponent<RectTransform>().rect.height;
itemWidth = itemPrefab.GetComponent<RectTransform>().rect.width;
if (nameHead == "")
{
nameHead = itemPrefab.name;
}
inited = true;
}
public void SetUpdateItemFunc(Action<GameObject, int> callBack)
{
itemUpdateCallBack = callBack;
}
private void UpdateSize()
{
if (mScrollRect.horizontal && !mScrollRect.vertical)
{
calItemNum = Math.Abs((int)Math.Floor(this.GetComponent<RectTransform>().rect.size.x / itemWidth)) + 2;
m_Direction = ScrollRect_Direction.Horizontal;
}
else if (!mScrollRect.horizontal && mScrollRect.vertical)
{
m_Direction = ScrollRect_Direction.Vertical;
calItemNum = Math.Abs((int)Math.Floor(this.GetComponent<RectTransform>().rect.size.y / itemHeight)) + 2;
}
else
{
Debug.LogError("not support both scroll type");
}
}
public void InitScrollViewData(int dataCount)
{
if (!inited) Init();
UpdateSize();
datasNum = dataCount;
if (m_Direction == ScrollRect_Direction.Vertical)
{
mContentRect.sizeDelta = new Vector2(mContentRect.sizeDelta.x, (itemHeight + space) * datasNum);
}
else if (m_Direction == ScrollRect_Direction.Horizontal)
{
mContentRect.sizeDelta = new Vector2((itemWidth + space) * datasNum, mContentRect.sizeDelta.y);
}
if (dataCount == 0)
{
for (int i = 0; i < itemList.Count; i++)
{
ReturnGameObjectToPool(itemList[i].gameObject);
}
}
else
{
FreshItemChilds();
}
}
//fresh item num
private void FreshItemChilds()
{
ready = false;
if (calItemNum > datasNum)
{ //自动计算的数量比数据个数多,只需要实例化数据个数的物体
needItemNum = datasNum;
}
else
{//否则按照自动计算的个数实例化物体
needItemNum = calItemNum;
}
for (int i = 0; i < itemList.Count; i++)
{
ReturnGameObjectToPool(itemList[i].gameObject);
}
firstIndex = 0;
itemList.Clear();
for (int i = 0; i < needItemNum; i++)
{
GameObject obj = GetGameObjectFromPool();
if (obj == null)
{
obj = Instantiate(itemPrefab);
}
obj.transform.SetParent(mContentRect.transform);
obj.name = nameHead + i.ToString();
RectTransform rectTrans = obj.GetComponent<RectTransform>();
rectTrans.localScale = Vector3.one;
if (m_Direction == ScrollRect_Direction.Vertical)
{
rectTrans.anchorMax = new Vector2(0.5f, 1);
rectTrans.anchorMin = new Vector2(0.5f, 1);
rectTrans.pivot = new Vector2(0.5f, 1);
rectTrans.anchoredPosition = new Vector2(0, -(itemHeight + space) * i);
}
else if (m_Direction == ScrollRect_Direction.Horizontal)
{
rectTrans.anchorMax = new Vector2(0, 1);
rectTrans.anchorMin = new Vector2(0, 1);
rectTrans.pivot = new Vector2(0f, 1f);
rectTrans.anchoredPosition = new Vector2((itemWidth + space) * i, 0);
}
obj.gameObject.SetActive(true);
lastIndex = i;
itemList.Add(obj);
itemUpdateCallBack(obj.gameObject, i);
}
ready = true;
}
private void OnScrollMove(Vector2 pVec)
{
if (!ready) return;
if (m_Direction == ScrollRect_Direction.Horizontal)//左右滚动
{
Debug.Log(mContentRect.anchoredPosition.x + " " + firstIndex + " " + lastIndex);
if (mContentRect.anchoredPosition.x < -(firstIndex + 1) * (itemWidth + space) && lastIndex != datasNum - 1)
{
GameObject first = itemList[0];
RectTransform rectTrans = first.GetComponent<RectTransform>();
itemList.RemoveAt(0);
itemList.Add(first);
rectTrans.anchoredPosition = new Vector2((lastIndex + 1) * (itemWidth + space), 0);
firstIndex += 1;
lastIndex += 1;
first.name = nameHead + lastIndex.ToString();
itemUpdateCallBack(first.gameObject, lastIndex);
}
if (mContentRect.anchoredPosition.x > -firstIndex * (itemWidth + space) && firstIndex != 0)
{
GameObject last = itemList[itemList.Count - 1];
RectTransform rectTrans = last.GetComponent<RectTransform>();
itemList.RemoveAt(itemList.Count - 1);
itemList.Insert(0, last);
rectTrans.anchoredPosition = new Vector2((firstIndex - 1) * (itemWidth + space), 0);
firstIndex -= 1;
lastIndex -= 1;
last.name = nameHead + firstIndex.ToString();
itemUpdateCallBack(last.gameObject, firstIndex);
}
return;
}
//向上滚动,视口的y坐标大于当前第一个序号*子物体高度得出对应高度值
if (mContentRect.anchoredPosition.y > (firstIndex + 1) * (itemHeight + space) && lastIndex != datasNum - 1)
{
int step = Mathf.CeilToInt((mContentRect.anchoredPosition.y - (firstIndex + 1) * (itemHeight + space)) / (itemHeight + space));
for (int i = 0; i < step; i++)
{
GameObject first = itemList[0];
RectTransform rectTrans = first.GetComponent<RectTransform>();
//将首个物体移出List,再添加到List最后端
itemList.RemoveAt(0);
itemList.Add(first);
//将这个物体移到最下方
rectTrans.anchoredPosition = new Vector2(0, -(lastIndex + 1) * (itemHeight + space));
firstIndex += 1;
lastIndex += 1;
first.name = nameHead + lastIndex.ToString();
itemUpdateCallBack(first.gameObject, lastIndex);
if (lastIndex >= datasNum - reqItemNum)
{
if (mReqType == DragEvent.Down)
{
reqFunc?.Invoke();
}
break;
}
}
}
//向下滚动
if (mContentRect.anchoredPosition.y < firstIndex * (itemHeight + space) && firstIndex != 0)
{
int step = Mathf.CeilToInt(((firstIndex + 1) * (itemHeight + space) - mContentRect.anchoredPosition.y) / (itemHeight + space));
for (int i = 0; i < step; i++)
{
GameObject last = itemList[itemList.Count - 1];
RectTransform rectTrans = last.GetComponent<RectTransform>();
itemList.RemoveAt(itemList.Count - 1);
itemList.Insert(0, last);
rectTrans.anchoredPosition = new Vector2(0, -(firstIndex - 1) * (itemHeight + space));
firstIndex -= 1;
lastIndex -= 1;
last.name = nameHead + firstIndex.ToString();
itemUpdateCallBack(last.gameObject, firstIndex);
if (firstIndex <= reqItemNum)
{
if (mReqType == DragEvent.Up)
{
reqFunc?.Invoke();
}
break;
}
}
}
}
private Utils.Util.NoneParamFunction reqFunc;
private DragEvent mReqType;
//1-到顶请求 2- 到底请求
public void SetReqDataEvent(DragEvent reqType, Utils.Util.NoneParamFunction callback, int reqNum)
{
mReqType = reqType;
reqFunc = callback;
reqItemNum = reqNum;
}
public void TopOnIndex(int targetIndex, bool center = false, Utils.Util.NoneParamFunction callback = null)
{
Utils.Util.DelayExecute(() =>
{
if (firstIndex == targetIndex || targetIndex >= datasNum || (datasNum - firstIndex) < needItemNum)
{//就在第一;数组越界;下面不够移动,上面不多(比如最后一个不能移动到最上面)
//Debug.LogError("不够移动" + firstIndex + " -" + targetIndex + " =" + datasNum + " ..>" + needItemNum);
//不需要移动的情况直接执行回调
callback?.Invoke();
return;
}
float halfSize = 0;
if (needItemNum % 2 == 0 && center)
{
halfSize = (itemHeight + space) / 2;
}
mContentRect.GetComponent<RectTransform>().localPosition = new Vector3(mContentRect.GetComponent<RectTransform>().localPosition.x, (targetIndex + 1) * (itemHeight + space) + halfSize, mContentRect.GetComponent<RectTransform>().localPosition.z);
callback?.Invoke();
}, () =>
{
return ready;
});
}
public void CenterOnIndex(int targetIndex, Utils.Util.NoneParamFunction callback = null)
{
TopOnIndex(targetIndex - needItemNum / 2 + 1, true, callback);
}
private void ReturnGameObjectToPool(GameObject obj)
{
if (gameObjectList.IndexOf(obj) == -1)
{
obj.transform.parent = null;
obj.gameObject.SetActive(false);
gameObjectList.Add(obj);
}
else
{
obj.gameObject.SetActive(false);
}
}
private GameObject GetGameObjectFromPool()
{
if (gameObjectList.Count > 0)
{
GameObject obj = gameObjectList[gameObjectList.Count - 1];
gameObjectList.RemoveAt(gameObjectList.Count - 1);
return obj;
}
return null;
}
public void ForceFresh()
{
int num = mContentRect.childCount;
for (int i = 0; i < num; i++)
{
GameObject c = mContentRect.GetChild(i).gameObject;
itemUpdateCallBack(c, firstIndex + i);
}
}
}
好了,就这样.