Unity无限滑动列表

利用Unity的Scroll Rect 实现无限滑动列表

利用unity自带的组件 Scroll ViewScroll Rect 来实现无限滑动列表

实现原理

  1. 利用有限的物体来实现无限滑动
  2. 利用滑出显示区域物体的位置调整来实现无限滑动
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

实现代码

无限滑动的主体功能

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

public class SlideList : MonoBehaviour
{
    private ScrollRect mScrollRect;
    private RectTransform mRect;
    public RectTransform Item;
    public Direction Dir;
    public uint mCount;
    /// <summary>
    /// Item的间隔
    /// </summary>
    public float mItemInterval;
    /// <summary>
    /// 是否参与计算
    /// </summary>
    private bool mCalcul;
    /// <summary>
    /// 间隔
    /// </summary>
    private float mInterval;
    /// <summary>
    /// 当前最小的索引
    /// </summary>
    private uint mMinIndex;
    /// <summary>
    /// 当前最大的索引
    /// </summary>
    private uint mMaxIndex;
    private uint mMaxShowCount;

    private List<SlideItem> mList = new List<SlideItem>();

    private void Awake()
    {
        Item.gameObject.SetActive(false);


        mScrollRect = this.GetComponentInParent<ScrollRect>();
        var TempRect = mScrollRect.GetComponent<RectTransform>();

        mRect = this.gameObject.GetComponent<RectTransform>();
        Vector2 size = mRect.sizeDelta;
        switch (Dir)
        {
            case Direction.Horizontal:
                //设置Content的对齐方向
                mRect.anchorMin = new Vector2(0, 0);
                mRect.anchorMax = new Vector2(0, 1);
                //计算间隔
                mInterval = Item.rect.size.x + mItemInterval;
                //计算滑动最大区间
                size.x = mInterval * mCount;
                mCalcul = size.x > TempRect.sizeDelta.x;
                //计算最大显示的数量
                mMaxShowCount = (uint)(TempRect.rect.size.x / Item.sizeDelta.x + 2);
                break;
            case Direction.Vertical:
                //设置Content的对齐方向
                mRect.anchorMin = new Vector2(0, 1);
                mRect.anchorMax = new Vector2(1, 1);
                //计算间隔
                mInterval = Item.rect.size.y + mItemInterval;
                //计算滑动最大区间
                size.y = mInterval * mCount;
                mCalcul = size.y > TempRect.sizeDelta.y;
                //计算最大显示的数量
                mMaxShowCount = (uint)(TempRect.rect.size.y / Item.sizeDelta.y + 2);
                break;
            default:
                break;
        }
        mRect.sizeDelta = size;
        mRect.localPosition = Vector3.zero;
        int index = 0;
        for (int i = 0; i < mMaxShowCount; i++)
        {
            if (i > mCount)
                break;
            index++;
            GameObject TempGame = GameObject.Instantiate<GameObject>(Item.gameObject);
            TempGame.transform.SetParent(Item.parent);
            TempGame.transform.localPosition = GetPos((int)i);
            TempGame.transform.localEulerAngles = Vector3.zero;
            TempGame.transform.localScale = Vector3.one;

            TempGame.gameObject.SetActive(true);
            SlideItem tempItem = TempGame.AddComponent<SlideItem>();
            tempItem.To(0, (uint)(i));
            mMaxIndex++;
            mList.Add(tempItem);
        }
        mMinIndex = 0;
    }


    private void Update()
    {
        if (mCalcul)
        {
            float index = 0;
            switch (Dir)
            {
                case Direction.Horizontal:
                    index = Mathf.Abs(mRect.localPosition.x) / mInterval;
                    break;
                case Direction.Vertical:
                    index = Mathf.Abs(mRect.localPosition.y) / mInterval;
                    break;
                default:
                    break;
            }
            if (index - mMinIndex >= 2)
            {
                if (index - mMinIndex >= mMaxShowCount)
                {
                    //滑动过快-直接设置
                    if (index <= mCount - mMaxShowCount)
                    {
                        int idx = (int)(mCount - mMaxShowCount);
                        for (int i = 0; i < mList.Count; i++)
                        {
                            var item = mList[i];

                            item.transform.localPosition = GetPos((int)(i + idx));
                            item.To(item.ID, (uint)(i + idx));
                        }
                        mMaxIndex = mCount;
                        mMinIndex = mCount - mMaxShowCount;
                    }
                    else
                    {
                        for (int i = 0; i < mList.Count; i++)
                        {
                            var item = mList[i];

                            item.transform.localPosition = GetPos((int)(i + index));
                            item.To(item.ID, (uint)(i + index));
                        }
                        mMinIndex = (uint)index;
                        mMaxIndex = mMinIndex + mMaxShowCount;
                    }
                }
                else if (mMaxIndex < mCount)
                {
                    int indexid = 0;
                    var item = mList[indexid];
                    mList.RemoveAt(indexid);

                    item.transform.localPosition = GetPos((int)mMaxIndex);
                    item.To(mMinIndex, mMaxIndex);
                    mMinIndex += 1;
                    mMaxIndex += 1;
                    mList.Add(item);
                }
            }
            else if (mMinIndex - index >= 0)
            {
                if (mMinIndex - index >= mMaxShowCount)
                {
                    //滑动过快-直接设置
                    for (int i = 0; i < mList.Count; i++)
                    {
                        var item = mList[i];

                        item.transform.localPosition = GetPos((int)(i + index));
                        item.To(item.ID, (uint)(i + index));
                    }
                    mMinIndex = (uint)index;
                    mMaxIndex = mMinIndex + mMaxShowCount;
                }
                else if (mMinIndex > 0)
                {
                    int indexid = (int)(mList.Count - 1);
                    var item = mList[indexid];
                    mList.RemoveAt(indexid);
                    mMinIndex -= 1;
                    mMaxIndex -= 1;

                    item.transform.localPosition = GetPos((int)mMinIndex);
                    item.To(mMaxIndex, mMinIndex);
                    mList.Insert((int)0, item);
                }
            }
        }
    }

    private Vector3 GetPos(int index)
    {
        Vector3 pos = Vector3.zero;
        switch (Dir)
        {
            case Direction.Horizontal:
                pos = new Vector3((mInterval / 2 + (index) * mInterval), Item.localPosition.y);
                break;
            case Direction.Vertical:
                pos = new Vector3(Item.localPosition.x, -(mInterval / 2 + index * mInterval));
                break;
            default:
                break;
        }
        //Debug.LogError(pos);
        return pos;
    }


    public enum Direction
    {
        Horizontal,
        Vertical,
    }
}

无限滑动的协助功能

可以继承该类来实现滑动后的数据刷新功能

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

public class SlideItem : MonoBehaviour
{
    public uint ID;
    
    public void To(uint Form,uint To)
    {
        ID = To;
        if (mText != null)
        {
            mText.text = To.ToString();
        }
        this.gameObject.name = To.ToString();
    }
}

Demo

滑动了列表的Demo
百度云盘路径
提取码:un1d

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值