直接上效果
脚本UGUIWrapContent.cs
///
/// 循环利用列表子项
/// Author: LXF
///
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
[RequireComponent(typeof(GridLayoutGroup))]
public class UGUIWrapContent : MonoBehaviour
{
protected void Awake()
{
m_hasInit = false;
m_realChildObjCnt = 0;
m_realIndex = -1;
m_realIndexUp = -1;
m_selfTrans = transform;
m_childsAnchoredPos = new Dictionary();
m_childsSiblingIndex = new Dictionary();
m_childrenRectTransList = new List();
}
IEnumerator InitChildren()
{
yield return 0;
bool needReDraw = false;
if (!m_hasInit)
{
FirstTimeInit();
needReDraw = true;
}
else
{
bool needReLocate = false;
if (m_realChildObjCnt >= m_dataChildCnt)
{
needReDraw = true;
needReLocate = true;
}
if (needReLocate)
{
ResetChildrenPos();
}
}
if (needReDraw)
{
ReDrawChildren();
}
}
private void FirstTimeInit()
{
//获取Grid的宽度;
m_rectTrans = GetComponent();
m_gridLayoutGroup = GetComponent();
m_gridLayoutGroup.enabled = false;
m_gridLayoutPos = m_rectTrans.anchoredPosition;
m_gridLayoutSize = m_rectTrans.sizeDelta;
//注册ScrollRect滚动回调;
if (null != m_scrollRect)
m_scrollRect.onValueChanged.AddListener((data) => { ScrollCallback(data); });
else
Debug.LogError("null == ScrollRect,请给脚本的ScrollRect赋值");
m_realChildObjCnt = m_selfTrans.childCount;
//获取所有child anchoredPosition 以及 SiblingIndex;
for (int index = 0, cnt = m_selfTrans.childCount; index < cnt; index++)
{
Transform child = m_selfTrans.GetChild(index);
RectTransform childRectTrans = child.GetComponent();
m_childsAnchoredPos.Add(child, childRectTrans.anchoredPosition);
m_childsSiblingIndex.Add(child, child.GetSiblingIndex());
}
}
private void ResetChildrenPos()
{
m_rectTrans.anchoredPosition = m_gridLayoutPos;
m_rectTrans.sizeDelta = m_gridLayoutSize;
m_childrenRectTransList.Clear();
m_realIndex = -1;
m_realIndexUp = -1;
//children重新设置上下顺序;
foreach (var info in m_childsSiblingIndex)
{
info.Key.SetSiblingIndex(info.Value);
}
//children重新设置anchoredPosition;
for (int index = 0; index < m_selfTrans.childCount; index++)
{
Transform child = m_selfTrans.GetChild(index);
RectTransform childRectTrans = child.GetComponent();
if (m_childsAnchoredPos.ContainsKey(child))
{
childRectTrans.anchoredPosition = m_childsAnchoredPos[child];
}
else
{
Debug.LogError("childsAnchoredPosition no contain " + child.name);
}
}
}
private void ReDrawChildren()
{
//获取所有child;
for (int index = 0; index < m_selfTrans.childCount; index++)
{
Transform trans = m_selfTrans.GetChild(index);
trans.gameObject.SetActive(true);
m_childrenRectTransList.Add(m_selfTrans.GetChild(index).GetComponent());
//初始化前面几个;
UpdateChildrenCallback(m_childrenRectTransList.Count - 1, m_selfTrans.GetChild(index));
}
m_startPos = m_rectTrans.anchoredPosition;
m_realIndex = m_childrenRectTransList.Count - 1;
m_hasInit = true;
//如果需要显示的个数小于设定的个数;
for (int index = 0; index < m_realChildObjCnt; index++)
{
m_childrenRectTransList[index].gameObject.SetActive(index < m_dataChildCnt);
}
if (m_gridLayoutGroup.constraint == GridLayoutGroup.Constraint.FixedColumnCount)
{
//如果小了一行,则需要把GridLayout的高度减去一行的高度;
int row = m_realChildObjCnt - m_dataChildCnt;
if (row > 0)
{
m_rectTrans.sizeDelta -= new Vector2(0, (m_gridLayoutGroup.cellSize.y + m_gridLayoutGroup.spacing.y) * row);
}
}
else
{
//如果小了一列,则需要把GridLayout的宽度减去一列的宽度;
int column = m_realChildObjCnt - m_dataChildCnt;
if (column > 0)
{
m_rectTrans.sizeDelta -= new Vector2((m_gridLayoutGroup.cellSize.x + m_gridLayoutGroup.spacing.x) * column, 0);
}
}
}
void ScrollCallback(Vector2 data)
{
UpdateChildren();
}
void UpdateChildren()
{
if (m_selfTrans.childCount < m_realChildObjCnt)
{
return;
}
Vector2 currentPos = m_rectTrans.anchoredPosition;
if (m_gridLayoutGroup.constraint == GridLayoutGroup.Constraint.FixedColumnCount)
{
float offsetY = currentPos.y - m_startPos.y;
if (offsetY > 0)
{
if (!OnMoveUp(currentPos)) return;
}
else
{
//向下拉,下面收缩;
if (!OnMoveDown(currentPos)) return;
}
}
else
{
float offsetX = currentPos.x - m_startPos.x;
if (offsetX < 0)
{
//向左拉,向右扩展;
if (!OnMoveLeft(currentPos)) return;
}
else
{
//向右拉,右边收缩;
if (!OnMoveRight(currentPos)) return;
}
}
m_startPos = currentPos;
}
private bool OnMoveUp(Vector2 currentPos)
{
//向上拉,向下扩展;
if (m_realIndex >= m_dataChildCnt - 1)
{
m_startPos = currentPos;
return false;
}
float scrollRectUp = m_scrollRect.transform.TransformPoint(Vector3.zero).y;
var topChild = m_childrenRectTransList[0];
var bottomChild = m_childrenRectTransList[m_childrenRectTransList.Count - 1];
Vector3 childBottomLeft = new Vector3(topChild.anchoredPosition.x, topChild.anchoredPosition.y - m_gridLayoutGroup.cellSize.y, 0f);
float childBottom = m_selfTrans.TransformPoint(childBottomLeft).y;
if (childBottom >= scrollRectUp)
{
//移动到底部//
topChild.SetAsLastSibling();
var posY = bottomChild.anchoredPosition.y - m_gridLayoutGroup.cellSize.y - m_gridLayoutGroup.spacing.y;
topChild.anchoredPosition = new Vector2(topChild.anchoredPosition.x, posY);
m_realIndex++;
if (m_realIndex > m_dataChildCnt - 1)
{
topChild.gameObject.SetActive(false);
}
else
{
UpdateChildrenCallback(m_realIndex, topChild);
}
//GridLayoutGroup 底部加长;
m_rectTrans.sizeDelta += new Vector2(0, m_gridLayoutGroup.cellSize.y + m_gridLayoutGroup.spacing.y);
//更新child;
RetTagChildren();
}
return true;
}
private bool OnMoveDown(Vector2 currentPos)
{
if (m_realIndex + 1 <= m_childrenRectTransList.Count)
{
m_startPos = currentPos;
return false;
}
RectTransform scrollRectTransform = m_scrollRect.GetComponent();
Vector3 scrollRectAnchorBottom = new Vector3(0, -scrollRectTransform.rect.height - m_gridLayoutGroup.spacing.y, 0f);
float scrollRectBottom = m_scrollRect.transform.TransformPoint(scrollRectAnchorBottom).y;
var lastChild = m_childrenRectTransList[m_childrenRectTransList.Count - 1];
Vector2 childUpLeft = lastChild.anchoredPosition + new Vector2(0, m_gridLayoutGroup.cellSize.y);
float childUp = m_selfTrans.TransformPoint(childUpLeft).y;
if (childUp < scrollRectBottom)
{
//把底部的一行 移动到顶部
var childCnt = m_childrenRectTransList.Count;
var bottomChild = m_childrenRectTransList[childCnt - 1];
var topChild = m_childrenRectTransList[0];
bottomChild.SetAsFirstSibling();
var posY = topChild.anchoredPosition.y + m_gridLayoutGroup.cellSize.y + m_gridLayoutGroup.spacing.y;
bottomChild.anchoredPosition = new Vector2(bottomChild.anchoredPosition.x, posY);
bottomChild.gameObject.SetActive(true);
UpdateChildrenCallback(m_realIndex - childCnt, bottomChild);
--m_realIndex;
//GridLayoutGroup 底部缩短;
m_rectTrans.sizeDelta -= new Vector2(0, m_gridLayoutGroup.cellSize.y + m_gridLayoutGroup.spacing.y);
//更新child;
RetTagChildren();
}
return true;
}
private bool OnMoveLeft(Vector2 currentPos)
{
if (m_realIndex >= m_dataChildCnt - 1)
{
m_startPos = currentPos;
return false;
}
float scrollRectLeft = m_scrollRect.transform.TransformPoint(Vector3.zero).x;
var leftestChild = m_childrenRectTransList[0];
var leftestChildPos = leftestChild.anchoredPosition;
var rightestChild = m_childrenRectTransList[m_childrenRectTransList.Count - 1];
Vector3 childBottomRight = new Vector3(leftestChildPos.x + m_gridLayoutGroup.cellSize.x, leftestChildPos.y, 0f);
float childRight = m_selfTrans.TransformPoint(childBottomRight).x;
if (childRight <= scrollRectLeft)
{
//移动到右边;
leftestChild.SetAsLastSibling();
var posX = rightestChild.anchoredPosition.x + m_gridLayoutGroup.cellSize.x + m_gridLayoutGroup.spacing.x;
leftestChild.anchoredPosition = new Vector2(posX, leftestChildPos.y);
m_realIndex++;
if (m_realIndex > m_dataChildCnt - 1)
{
leftestChild.gameObject.SetActive(false);
}
else
{
UpdateChildrenCallback(m_realIndex, m_childrenRectTransList[0]);
}
//GridLayoutGroup 右侧加长;
m_rectTrans.sizeDelta += new Vector2(m_gridLayoutGroup.cellSize.x + m_gridLayoutGroup.spacing.x, 0);
//更新child;
RetTagChildren();
}
return true;
}
private bool OnMoveRight(Vector2 currentPos)
{
if (m_realIndex + 1 <= m_childrenRectTransList.Count)
{
m_startPos = currentPos;
return false;
}
var rightestChild = m_childrenRectTransList[m_childrenRectTransList.Count - 1];
var rightestChildPos = rightestChild.anchoredPosition;
var leftestChild = m_childrenRectTransList[0];
RectTransform scrollRectTransform = m_scrollRect.GetComponent();
Vector3 scrollRectAnchorRight = new Vector3(scrollRectTransform.rect.width + m_gridLayoutGroup.spacing.x, 0, 0f);
float scrollRectRight = m_scrollRect.transform.TransformPoint(scrollRectAnchorRight).x;
Vector2 childUpLeft = rightestChildPos - new Vector2(m_gridLayoutGroup.cellSize.x, 0);
float childLeft = m_selfTrans.TransformPoint(childUpLeft).x;
if (childLeft >= scrollRectRight)
{
//把右边的一行 移动到左边;
rightestChild.SetAsFirstSibling();
var posX = leftestChild.anchoredPosition.x - m_gridLayoutGroup.cellSize.x - m_gridLayoutGroup.spacing.x;
rightestChild.anchoredPosition = new Vector2(posX, rightestChildPos.y);
rightestChild.gameObject.SetActive(true);
UpdateChildrenCallback(m_realIndex - m_childrenRectTransList.Count, rightestChild);
--m_realIndex;
//GridLayoutGroup 右侧缩短;
m_rectTrans.sizeDelta -= new Vector2(m_gridLayoutGroup.cellSize.x + m_gridLayoutGroup.spacing.x, 0);
//更新child;
RetTagChildren();
}
return true;
}
private void RetTagChildren()
{
for (int index = 0, cnt = m_childrenRectTransList.Count; index < cnt; ++index)
{
var child = m_selfTrans.GetChild(index);
m_childrenRectTransList[index] = child.GetComponent();
}
}
void UpdateChildrenCallback(int index, Transform trans)
{
if (updateChildrenCallback != null)
{
updateChildrenCallback(index, trans);
}
}
///
/// 设置总的个数;
///
///
public void SetAmount(int count)
{
m_dataChildCnt = count;
StartCoroutine(InitChildren());
}
///
/// 是否初始化过
///
private bool m_hasInit = false;
///
/// 实际的子项Obj数量
///
private int m_realChildObjCnt;
///
/// 数据子项数量
///
private int m_dataChildCnt;
private RectTransform m_rectTrans;
private Transform m_selfTrans;
private GridLayoutGroup m_gridLayoutGroup;
private List m_childrenRectTransList;
private Vector2 m_startPos;
private int m_realIndex;
private int m_realIndexUp;
private Vector2 m_gridLayoutSize;
private Dictionary m_childsAnchoredPos;
private Vector2 m_gridLayoutPos;
private Dictionary m_childsSiblingIndex;
[SerializeField]
private ScrollRect m_scrollRect;
public delegate void UpdateChildrenCallbackDelegate(int index, Transform trans);
public UpdateChildrenCallbackDelegate updateChildrenCallback = null;
}
///
/// 列表子项画师
/// Author: LXF
///
using UnityEngine;
using UnityEngine.UI;
public class ScrollListDrawer : MonoBehaviour
{
UGUIWrapContent infinityGridLayoutGroup;
int amount = 10;
void Start()
{
//初始化数据列表//
infinityGridLayoutGroup = transform.GetComponent();
infinityGridLayoutGroup.SetAmount(amount);
infinityGridLayoutGroup.updateChildrenCallback = UpdateChildrenCallback;
}
void OnGUI()
{
if (GUILayout.Button("Add one item"))
{
infinityGridLayoutGroup.SetAmount(++amount);
}
}
void UpdateChildrenCallback(int index, Transform trans)
{
OnDraw(index, trans);
}
private void OnDraw(int index, Transform trans)
{
Text text = trans.Find("Text").GetComponent();
text.text = index.ToString();
}
}