Unity ScrollView无限循环左右滑动翻页带阻尼效果

从https://blog.csdn.net/Sam_ONE/article/details/60467911借鉴优化而来

上面的例子是上下滑动,而且滑动的过程中,子节点的顺序会打乱,这里改成左右滑动,并且加了个排序,使滑动过程中子节点保持正确的顺序。把脚本挂在ScrollView上面,子节点加上Item脚本(随意实现)基本上就可以了

using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class MainScrollView : MonoBehaviour, IEndDragHandler, IBeginDragHandler
{
    private LTDescr lt;//需要导入LeanTween插件
    //[组件信息]
    private ScrollRect scrollRect;
    private Transform ContentObj;    //父节点
    private Item[] itemList;                //子节点管理

    //[UI效果设置参数]
    private float m_inertiaTime = 0f;    //惯性作用时间 
    private float m_BackTime = 0.3f;     //回弹时间
    private float m_startDecelert = 0.05f;//初始惯性加速度

    //[Item设置参数]
    private float itemWidth;               //子节点宽度
    private float m_CurPosX;                    //Content相对X位置(0为参考)
    private int m_Index = 0;                    //X位置与子节点宽度的整倍数
    private float m_Surplus = 0;                //X位置与子节点宽度的整倍后剩余
    private float MaxPosX = 0;                  //根据Item数量、间距、item宽度计算得到的X轴最大的数值
    private Vector3 m_StartPos;                 //记录每次需要居中前的Content位置
    private float m_OldPosX;
    //[Item包含数据相关]
    private int RealAmount;             //真实的ListCount
    private int IndexPlus;
    private int fistIndex = 0;
    private int lastIndex = 0;
    private int m_CurrentIndex = 0;
    private int m_PreviousIndex = 0;
    [SerializeField]
    private RectTransform content;

    void Awake()
    {
        if (!GetComponent())
        {
            gameObject.AddComponent();
            var scrollRect = GetComponent();
            scrollRect.vertical = false;
            scrollRect.movementType = ScrollRect.MovementType.Unrestricted;
            scrollRect.content = content;
        }
        scrollRect = GetComponent();
        ContentObj = scrollRect.content;
        itemWidth = GetComponent().sizeDelta.x;
        if (ContentObj.GetComponent())
            ContentObj.GetComponent().enabled = false;
        ContentObj.transform.localPosition = new Vector3(0, ContentObj.localPosition.y);
        if (GetComponent())
            GetComponent().raycastTarget = true;
    }

    // Use this for initialization
    void Start()
    {
        //Content下的子物体排序,使子物体在拖动时保持顺序
        Item[] items = ContentObj.GetComponentsInChildren();
        int itemsLen = items.Length;
        Item[] itemsTmp = new Item[itemsLen];
        int index = (itemsLen - 1) / 2;
        for (int i = 0; i < itemsLen; i++)
        {
            itemsTmp[i] = items[(index - i) >= 0 ? index - i : itemsLen + index - i];
        }
        RefreshMusicList(itemsTmp);
    }

    /// 
    /// Content的初始位置X赋值
    /// 
    void ContentPointInit()
    {
        if (ContentObj.childCount % 2 == 0)//判断子对象的奇偶
        {
            ContentObj.localPosition = new Vector3(ContentObj.localPosition.x - (itemWidth / 2), ContentObj.localPosition.y, ContentObj.localPosition.z);
            m_OldPosX = -itemWidth / 2;
        }
    }

    // Update is called once per frame
    void Update()
    {
        m_PreviousIndex = m_CurrentIndex;
        CalculationContentChanege();
    }

    /// 
    /// 初始更新列表内容
    /// 
    /// 对象
    public void RefreshMusicList(Item[] Rr)
    {
        MaxPosX = Rr.Length / 2 * itemWidth;      //根据Item数量计算得到最顶上Item的Pos,用于往下一次推算之后的Pos
        if (Rr.Length % 2 == 0)
            MaxPosX -= itemWidth / 2;

        RealAmount = Rr.Length;
        gameObject.SetActive(true);

        itemList = Rr;
        for (int i = 0; i < itemList.Length; i++)
        {
            itemList[i].transform.localPosition = new Vector3(MaxPosX - i * itemWidth, 0, 0);
        }
        ContentPointInit();                     //更新列表初始位置
        fistIndex = 0;                          //记录首末序号
        lastIndex = RealAmount - 1;
    }


    /// 
    /// Item定位
    /// 
    public void LocateItem()
    {
        lt = LeanTween.value(0, 1, m_inertiaTime).setOnStart(() =>
        {
            scrollRect.decelerationRate = m_startDecelert;
        }).setOnUpdate((float f) =>
        {
            scrollRect.decelerationRate = Mathf.Lerp(m_startDecelert, 0, f);
        }).setOnComplete(() =>
        {
            lt = LeanTween.value(0, 1, m_BackTime).setOnStart(() =>
            {
                m_StartPos = ContentObj.localPosition;
                m_CurPosX = ContentObj.localPosition.x;
                m_Index = (int)(ContentObj.childCount % 2 == 0 ? (m_CurPosX + itemWidth / 2) / itemWidth : m_CurPosX / itemWidth);
                m_Surplus = m_CurPosX % itemWidth;
                if (m_CurPosX - m_OldPosX < 0)
                {
                    IndexPlus = m_CurPosX < 0 ? -1 : 0;
                }
                else
                {
                    if (ContentObj.childCount % 2 == 0) m_CurPosX += itemWidth / 2;
                    IndexPlus = m_CurPosX < 0 ? 0 : 1;
                }
                if (Mathf.Abs(m_Surplus) >= (itemWidth / 30))
                    m_Index += IndexPlus;
            }).setOnUpdate((float f) =>
            {
                float posX = m_Index * itemWidth;
                if (ContentObj.childCount % 2 == 0) posX = m_Index * itemWidth - (itemWidth / 2);
                ContentObj.localPosition = Vector3.Lerp(m_StartPos, new Vector3(posX, ContentObj.localPosition.y), f);
                m_OldPosX = ContentObj.localPosition.x;
            });
        });
    }

    void IEndDragHandler.OnEndDrag(PointerEventData eventData)
    {
        scrollRect.OnEndDrag(eventData);
        m_inertiaTime = Mathf.Clamp(Mathf.Clamp01(Math.Abs(eventData.delta.x * 0.008f)), 0, 0.1f);      //根据拖拽的速度限制惯性运行的时间
        LocateItem();
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        if (lt != null)
            lt.reset();
    }

    void Circulation(int _dir)
    {
        if (_dir > 0)
        {
            itemList[fistIndex].transform.localPosition = itemList[lastIndex].transform.localPosition - new Vector3(itemWidth, 0, 0);
            lastIndex = fistIndex;
            fistIndex = (fistIndex + 1) % RealAmount;
        }
        else if (_dir < 0)
        {
            itemList[lastIndex].transform.localPosition = itemList[fistIndex].transform.localPosition + new Vector3(itemWidth, 0, 0);
            fistIndex = lastIndex;
            lastIndex = (lastIndex + RealAmount - 1) % RealAmount;
        }
    }

    private void CalculationContentChanege()
    {
        m_CurrentIndex = Mathf.FloorToInt(ContentObj.localPosition.x / itemWidth);  //向下取整获得变化的Index!!!!!!!!!!
        if (m_PreviousIndex != m_CurrentIndex)
        {
            for (int i = 0; i < Mathf.Abs(m_CurrentIndex - m_PreviousIndex); i++)
                Circulation(m_CurrentIndex - m_PreviousIndex);
        }
    }
}

 

 

你可能感兴趣的:(Unity)