【Unity】ScrollRect滑动列表重复利用

水平或垂直可选

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIScrollRect : MonoBehaviour
{
    [Header("水平")]
    public bool Horizontal;
    [Header("垂直")]
    public bool Vertical;
    [Header("列数,行数")]
    public Vector2 Grid;                        //行列数
    [Header("单元格宽高")]
    public Vector2 CellSize;                    //单元格宽高
    [Header("单元格间隔")]
    public Vector2 Spacing;                     //间隔

    [Header("父物体")]
    public RectTransform m_ItemParentTrans;     //父物体
    [Header("预制体")]
    public GameObject m_Prefab;                 //预制体
    private int RowNum;                         //行数
    private int ColumnNum;                      //列数
    private int m_CreateCount;                  //显示创建数
    private int m_TotalCount;                   //Content显示总数量
    private int m_ShowCount;                    //实际显示数量
    private int m_LastStartIndex = 0;           //上次初始序号
    private int m_StartIndex = 0;               //初始序号
    private int m_EndIndex = 0;                 //结束序号
    
    private ScrollRect m_ScrollRect;            //滑动组件
    private RectTransform m_SelfRectTrans;
    private Dictionary<int, Transform> m_ItemIndexDic = new Dictionary<int, Transform>();     //Item对应得序号
    private List<int> m_NewIndexList = new List<int>();
    private List<int> m_ChangeIndexList = new List<int>();
    int[] intlist = { 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219
    ,220,221,222,223,224,225,226,227,228,229,230,231,232,233};
    void Start()
    {
        Init(intlist.Length);
        m_ScrollRect = GetComponent<ScrollRect>();
        if (m_ScrollRect != null)
        {
            m_ScrollRect.onValueChanged.AddListener(OnScrollRectChange);
            m_ScrollRect.horizontal = Horizontal;
            m_ScrollRect.vertical = Vertical;
        }
        m_SelfRectTrans = GetComponent<RectTransform>();
        //SetCorner();
    }

    //private void SetCorner()
    //{
    //    if (Vertical)
    //    {
    //        float x = (ColumnNum * CellSize.x + (ColumnNum - 1) * Spacing.x);
    //        Debug.Log(m_ItemParentTrans.localPosition.x);
    //        Debug.Log((m_ItemParentTrans.parent.localPosition.x + x));
    //        m_ItemParentTrans.localPosition = new Vector3(-(m_ItemParentTrans.parent.localPosition.x + x), m_ItemParentTrans.localPosition.y,0);
    //    }
    //}
    /// <summary>
    /// 初始化并构建
    /// </summary>
    /// <param name="totalCount"></param>
    public void Init(int totalCount)
    {
        ColumnNum = (int)Grid.x;
        RowNum = (int)Grid.y;
        if (ColumnNum <= 0 || RowNum <= 0)
            return;
        //预留三行或三列
        if (ColumnNum >= RowNum)
            ColumnNum += 3;
        else
            RowNum += 3;
        m_CreateCount = ColumnNum * RowNum;
        m_TotalCount = totalCount;
        m_ShowCount = Mathf.Min(m_TotalCount, m_CreateCount);

        int RectWidth, RectHeight;
        GetContentRect(out RectWidth,out RectHeight);
        m_ItemParentTrans.sizeDelta = new Vector2(RectWidth,RectHeight);
        for (int index = 0; index < m_ShowCount; ++index)
        {
            Transform transform = GetItemTransform(index);
            SetItemTransform(transform,index);
        }
        ShowOrHideItem(m_ItemParentTrans, m_ShowCount);
    }

    /// <summary>
    /// 获取Content宽高
    /// </summary>
    public void GetContentRect(out int RectWidth,out int RectHeight)
    {
        if (Horizontal)
        {
            RectHeight = (int)(RowNum * CellSize.y + (RowNum - 1) * Spacing.y);
            ColumnNum = m_TotalCount / RowNum + (m_TotalCount % RowNum > 0 ? 1 : 0);      //计算有多少行,用于计算出总高度
            RectWidth = (int)Mathf.Max(0, ColumnNum * CellSize.x + (ColumnNum - 1) * Spacing.x);
        }
        else if (Vertical)
        {
            RectWidth = (int)(ColumnNum * CellSize.x + (ColumnNum - 1) * Spacing.x);             //计算横向列宽                                                                  
            RowNum = m_TotalCount / ColumnNum + (m_TotalCount % ColumnNum > 0 ? 1 : 0);
            RectHeight = (int)Mathf.Max(0, RowNum * CellSize.y + (RowNum - 1) * Spacing.y);   //计算行数及Content的高度
        }
        else
        {
            RectWidth = 0;
            RectHeight = 0;
        }
    }
   
    /// <summary>
    /// 获取Item
    /// 有即复用,无则创建
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    private Transform GetItemTransform(int index)
    {
        Transform transform = null;
        //回滚(已有,复用)
        if(index < m_ItemParentTrans.childCount)
        {
            transform = m_ItemParentTrans.GetChild(index);
        }
        else
        {
            transform = Instantiate(m_Prefab).transform;
        }
        transform.name = index.ToString();
        transform.SetParent(m_ItemParentTrans);
        transform.localScale = Vector3.one;
        return transform;
    }
    /// <summary>
    /// 赋值Item
    /// </summary>
    /// <param name="transform"></param>
    /// <param name="index"></param>
    public void SetItemTransform(Transform transform, int index)
    {
        if (m_ItemIndexDic.ContainsKey(index))
            m_ItemIndexDic[index] = transform;
        else
            m_ItemIndexDic.Add(index, transform);
        transform.localPosition = GetItemPos(index);
        //更新属性
        transform.name = "Item_"+ intlist[index];
        transform.GetComponentInChildren<Text>().text = intlist[index].ToString();
    }
    /// <summary>
    /// 获取Item位置
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    private Vector2 GetItemPos(int index)
    {
        if(Horizontal)
            return new Vector2(index / RowNum * (CellSize.y + Spacing.x), -index % RowNum * (CellSize.x + Spacing.y));
        else if(Vertical)
            return new Vector2(index % ColumnNum * (Spacing.x + CellSize.x) ,-index / ColumnNum*(Spacing.y + CellSize.y));
        return Vector2.zero;
    }
    /// <summary>
    /// Item显隐
    /// </summary>
    /// <param name="parent"></param>
    /// <param name="count"></param>
    private void ShowOrHideItem(Transform parent,int count)
    {
        if (parent.childCount < count)
            return;
        for (int index = 0; index < count; index++)
        {
            if(index < count)
            {
                parent.GetChild(index).gameObject.SetActive(true);
            }
            else
            {
                parent.GetChild(index).gameObject.SetActive(false);
            }
        }
    }
 
    /// <summary>
    /// 检测滑动
    /// </summary>
    /// <param name="Pos"></param>
    private void OnScrollRectChange(Vector2 Pos)
    {
        if(m_TotalCount < m_CreateCount)
            return;
        m_StartIndex = GetStartIndex();
        if(m_StartIndex + m_CreateCount >= m_TotalCount)
        {
            m_StartIndex = m_TotalCount - m_CreateCount;
            m_EndIndex = m_TotalCount - 1;
        }
        else
        {
            m_EndIndex = m_StartIndex + m_CreateCount - 1;
        }
        if (m_StartIndex == m_LastStartIndex)
            return;
        m_LastStartIndex = m_StartIndex;
        m_NewIndexList.Clear();
        m_ChangeIndexList.Clear();
        for(int index = m_StartIndex;index <= m_EndIndex; ++index)
        {
            m_NewIndexList.Add(index);
        }
        foreach (var item in m_ItemIndexDic)
        {
            if(item.Key >= m_StartIndex && item.Key <= m_EndIndex)
            {
                if(m_NewIndexList.Contains(item.Key))
                {
                    m_NewIndexList.Remove(item.Key);
                }
            }
            else
            {
                m_ChangeIndexList.Add(item.Key);
            }
        }

        for (int index = 0; index < m_NewIndexList.Count && index < m_ChangeIndexList.Count; index++)
        {
            int oldIndex = m_ChangeIndexList[index];
            int newIndex = m_NewIndexList[index];
            if(newIndex >= 0 && newIndex < m_TotalCount)
            {
                Transform transform = m_ItemIndexDic[oldIndex];
                m_ItemIndexDic.Remove(oldIndex);
                SetItemTransform(transform, newIndex);
            }
        }
    }

    /// <summary>
    /// 获取起始下标
    /// </summary>
    /// <returns></returns>
    private int GetStartIndex()
    {   
        if (Horizontal)
        {
            float x = -m_ItemParentTrans.localPosition.x;//将负坐标转正 
            if (x <= CellSize.x)
                return 0;
            float scrollWidth = m_SelfRectTrans.sizeDelta.x;
            if (x >= (m_ItemParentTrans.sizeDelta.x - scrollWidth))        //拉到底部了
            {
                if (m_TotalCount <= m_CreateCount)
                    return 0;
                else
                    return m_TotalCount - m_CreateCount;
            }
            return (int)((x / (CellSize.x + Spacing.x)) + (x % (CellSize.x + Spacing.x) > 0 ? 1 : 0) - 1) * RowNum;
        }
        else if(Vertical)
        {
            float y = m_ItemParentTrans.localPosition.y;
            if (y <= CellSize.y)
                return 0;
            float scrollHeight = m_SelfRectTrans.sizeDelta.y;
            Debug.Log(m_ItemParentTrans.sizeDelta.y - scrollHeight);
            if (y >= (m_ItemParentTrans.sizeDelta.y - scrollHeight))
            {
                //显示全部了
                if (m_TotalCount <= m_CreateCount)
                    return 0;
                else
                {
                    //未显示结束
                    return m_TotalCount - m_CreateCount;
                }
            }
            return (int)((y / (CellSize.y + Spacing.y)) + (y % (CellSize.y + Spacing.y) > 0 ? 1 : 0) - 1) * ColumnNum;
        }
        return 0;
    }
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值