Unity UGUI ScrollView无限滚动效果

一、发现需求

1、在UGUI中,使用 ScrollView + 表格布局和字段自适应组件 就可以很好的实现列表功能。

2、如果列表中同时存在很多个Item时,显示区域却只显示一部分,就会造成性能不必要的浪费。

3、这时就想到,利用对象池相关知识,只在列表显示的地方实例化有限的Item即可。


二、实现原理

在列表滑动时,根据Content移动的位置偏差,计算出当前需要显示的Item索引,配合对象池,动态刷新Item数据。


三、实现需求

1、新建一个ScrollView,给物体添加CircularScrollRect脚本,设置好参数。

2、然后在其他脚本在合适的时机调用 CircularScrollRect 的 Init()、ShowAndUpdateList()、ClearScrollRectAllItem()等方法即可。


最终效果:


使用【customeditor特性】给CircularScrollRect脚本写了一个编辑器拓展,方便调参.

Unity UGUI ScrollView无限滚动效果_第1张图片


部分代码:

    /// 
    /// 滑动content,更新Item.
    /// 
    private void UpdateCheck()
    {
        if (m_ItemInfos == null) return;  //没有Item,不执行.
           
        //检查超出范围
        for (int i = 0, length = m_ItemInfos.Length; i < length; i++)
        {
            ItemInfo itemInfo = m_ItemInfos[i];
            GameObject obj = itemInfo.obj;
            Vector3 pos = itemInfo.pos;

            float posXY = m_Direction == ScrollRect_Direction.Vertical ? pos.y : pos.x;
            if (IsOutRange(posXY)) //超出显示范围.
            {
                //把超出范围的item 扔进 poolsObj里.
                if (obj != null)
                {
                    EnterPoolsObj(obj);
                    m_ItemInfos[i].obj = null;
                }
            }
            else    //在显示范围内.
            {
                //已在范围内的Item,不需要设置.
                if (obj == null)    
                {
                    GameObject item = GetPoolsObj();    //优先从 poolsObj中 取出. (poolsObj为空则返回 实例化的item)
                    item.transform.localPosition = pos;
                    item.gameObject.name = m_ItemName + "_" + i.ToString();
                    m_ItemInfos[i].obj = item;

                    ImplementActionMethod(m_itemUpdateCallBack, item);
                }
            }
        }
    }
    /// 
    /// 判断是否超出显示范围.
    /// 
    /// 垂直为Y,水平为X
    /// 
    private bool IsOutRange(float posXY)
    {
        Vector3 contentPos = m_Content_RTrans.anchoredPosition;

        #region if Item中心点在左上角.
        if (m_ItemPivot == Item_Pivot.LeftUp)                   //Item中心点在左上角.
        {
            if (m_Direction == ScrollRect_Direction.Vertical)   //垂直方向.
            {
                if (posXY + contentPos.y > m_ItemObj_Height ||         //上方超出范围.
                    posXY + contentPos.y < -m_RTrans.rect.height)      //下方超出范围.
                {
                    return true;
                }
            }
            else    //水平方向.
            { 
                if (posXY + contentPos.x < -m_ItemObj_Width ||         //左方超出范围.
                    posXY + contentPos.x > m_RTrans.rect.width)        //右方超出范围.
                {
                    return true;
                }
            }
            return false;
        }
        #endregion

        #region else if Item中心点在中央.
        else if (m_ItemPivot == Item_Pivot.Center)  //Item中心点在中央.
        {
            if (m_Direction == ScrollRect_Direction.Vertical)   //垂直方向.
            {
                if (posXY + (m_ItemObj_Height / 2) + contentPos.y > m_ItemObj_Height ||        //上方超出范围.
                    posXY + (m_ItemObj_Height / 2) + contentPos.y < -m_RTrans.rect.height)     //下方超出范围.
                {
                    return true;
                }
            }
            else    //水平方向.
            {
                if (posXY + (m_ItemObj_Width / 2) + contentPos.x < -m_ItemObj_Width ||        //左方超出范围.
                    posXY - (m_ItemObj_Width / 2) + contentPos.x > m_RTrans.rect.width)       //右方超出范围.
                {
                    return true;
                }
            }
            return false;
        }
        #endregion

        #region else Item中心点在其他位置.
        else    //Item中心点在其他位置.Obsolete
        {
            return true;
        }
        #endregion
    }


Github,项目代码

这是以前写的代码,当时阅览过不小博客资源,若有雷同,侵删,完毕.

你可能感兴趣的:(Unity)