UGUI 列表循环使用

直接上效果




脚本UGUIWrapContent.cs

/// <summary>
/// 循环利用列表子项
/// Author: LXF
/// </summary>

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<Transform, Vector2>();
        m_childsSiblingIndex = new Dictionary<Transform, int>();
        m_childrenRectTransList = new List<RectTransform>();
    }

    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<RectTransform>();

        m_gridLayoutGroup = GetComponent<GridLayoutGroup>();
        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<RectTransform>();
            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<RectTransform>();
            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<RectTransform>());

            //初始化前面几个;
            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<RectTransform>();
        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<RectTransform>();
        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<RectTransform>();
        }
    }

    void UpdateChildrenCallback(int index, Transform trans)
    {
        if (updateChildrenCallback != null)
        {
            updateChildrenCallback(index, trans);
        }
    }


    /// <summary>
    /// 设置总的个数;
    /// </summary>
    /// <param name="count"></param>
    public void SetAmount(int count)
    {
        m_dataChildCnt = count;

        StartCoroutine(InitChildren());
    }

    /// <summary>
    /// 是否初始化过
    /// </summary>
    private bool m_hasInit = false;

    /// <summary>
    /// 实际的子项Obj数量
    /// </summary>
    private int m_realChildObjCnt;
    /// <summary>
    /// 数据子项数量
    /// </summary>
    private int m_dataChildCnt;

    private RectTransform m_rectTrans;
    private Transform m_selfTrans;
    private GridLayoutGroup m_gridLayoutGroup;

    private List<RectTransform> m_childrenRectTransList;
    private Vector2 m_startPos;

    private int m_realIndex;
    private int m_realIndexUp;

    private Vector2 m_gridLayoutSize;
    private Dictionary<Transform, Vector2> m_childsAnchoredPos;
    private Vector2 m_gridLayoutPos;
    private Dictionary<Transform, int> m_childsSiblingIndex;

    [SerializeField]
    private ScrollRect m_scrollRect;

    public delegate void UpdateChildrenCallbackDelegate(int index, Transform trans);
    public UpdateChildrenCallbackDelegate updateChildrenCallback = null;
}

脚本ScrollListDrawer.cs

/// <summary>
/// 列表子项画师
/// Author: LXF
/// </summary>

using UnityEngine;
using UnityEngine.UI;

public class ScrollListDrawer : MonoBehaviour
{
    UGUIWrapContent infinityGridLayoutGroup;

    int amount = 10;

    void Start()
    {
        //初始化数据列表//
        infinityGridLayoutGroup = transform.GetComponent<UGUIWrapContent>();
        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.text = index.ToString();
    }

}




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林新发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值