ScrollView无限循环阻尼居中(带缩放)

       前两天写的SceollView阻尼居中的忘了加入循环列表的功能,本来我以为加入循环的功能不难,当写了才发现,因为上一个版本的Content里为了方便加的两个挂件(Content Size Fitter 和 Grid Layout Group)让我很尴尬,中间我试着实现了循环功能,发现在运行情况下我切换至VS后切换回Unity之后它又让我回到解放前(交换的Item位置又倍还原了。。),其中的原有我大概了解,但水平有限无法说明了。所以这次,我把它们卸了,自己给每个Item赋值,搞定!能力有限,写不出什么复用性高的代码。。。。。

之前忘记说,中间有一个AddChild()方法是自己写的拓展方法,只是为了方便一次性加入Item对象并返回所以子对象而写。
其中SignBox是放大区的标记点。

下面是代码:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using GameServer.Script.Model;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;

public class MusicScrollView : MonoBehaviour, IEndDragHandler, IBeginDragHandler
{
    LTDescr lt;
    private static MusicScrollView _instance;
    public static MusicScrollView Instance
    {
        get
        {
            if (_instance == null)
            {
                GameObject go = new GameObject();
                _instance = go.AddComponent<MusicScrollView>();
            }
            return _instance;
        }

    }


    //[组件信息]
    ScrollRect scrollRect;
    public DicItem ItemObj;             //Item
    public GameObject SingBox;          //标记盒子          
    private Transform ContentObj;       //父节点
    List<DicItem> itemList;             //子节点管理

    //[UI效果设置参数]
    private float m_inertiaTime = 0f;    //惯性作用时间 
    private float m_BackTime = 0.3f;     //会弹时间
    private float m_startDecelert = 0.05f;//初始惯性加速度
    private float m_UpRange = 0.4f;      //放大检测范围及Scale增量

    //[Item设置参数]
    float m_SpaceBetween;               //设置的碟片中心点间距
    float m_ParentStarPosY;             //Content初始Y位置
    float m_CurPosY;                    //Content相对Y位置(0为参考)
    float ItemHeight = 300;             //碟片高度
    float SpaceY = 180;                 //碟片边缘之间的间距
    int m_Index = 0;                    //Y位置与碟片(高度+间距)的整倍数
    float m_Surplus = 0;                //Y位置与碟片(高度+间距)的整倍后剩余
    float MaxPosY = 0;                  //根据Item数量、间距、item高度计算得到的Y轴最大的数值
    Vector3 m_StartPos;                 //记录每次需要居中前的Content位置

    //[Item包含数据相关]
    [HideInInspector]
    public DicItem SelectDic;           //选中碟片歌曲信息
    private int SelectItem;             //选中歌曲在Content下的排列序号
    private int RealAmount;             //真实的List<ResResut>Count

    //[计算相关数值]
    private int Direct = 0;
    private Vector3 lastPos;
    private Vector3 firstPos;
    int fistIndex = 0;
    int lastIndex = 0;
    Vector3[] PosArra;

    void Awake()
    {
        _instance = this;
        scrollRect = GetComponent<ScrollRect>();
        ContentObj = scrollRect.content;
    }

    // Use this for initialization
    void Start()
    {
        m_SpaceBetween = SpaceY + ItemHeight;// ContentObj.GetComponent<GridLayoutGroup>().spacing.y + m_ItemHight;
    }

    /// <summary>
    /// Content的初始位置Y赋值
    /// </summary>
    void ContentPointInit()
    {
        if (ContentObj.childCount % 2 == 0)//判断子对象的奇偶(上一次亦为奇数)
        {
            ContentObj.localPosition = new Vector3(ContentObj.localPosition.x, ContentObj.localPosition.y - (m_SpaceBetween / 2), ContentObj.localPosition.z);
        }
        else if (ContentObj.childCount % 2 != 0)
        {
        }
        m_ParentStarPosY = ContentObj.localPosition.y;
    }

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

    /// <summary>
    /// 初始更新列表内容
    /// </summary>
    /// <param name="Rr">对象</param>
    public void RefreshMusicList(List<ResResut> Rr)
    {
        MaxPosY = (Rr.Count / 2) * m_SpaceBetween;      //根据Item数量计算得到最顶上Item的Pos,用于往下一次推算之后的Pos
        if (Rr.Count % 2 == 0)
            MaxPosY -= m_SpaceBetween / 2;

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

        itemList = ContentObj.AddChild<DicItem>(ItemObj.gameObject, Rr.Count).ToList();//数组转List
        for (int i = 0; i < itemList.Count; i++)
        {
            if (Rr[i].ResType == 1)
                itemList[i].Init(Rr[i], i % 3); //专辑封面零时
            itemList[i].transform.localPosition = new Vector3(0, MaxPosY - i * m_SpaceBetween, 0);     //便利赋值所有子对象的LocaPos
        }
        ContentPointInit();                     //更新列表初始位置
        fistIndex = 0;                          //记录首末序号
        lastIndex = RealAmount - 1;
    }

    /// <summary>
    /// Item定位
    /// </summary>
    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_CurPosY = ContentObj.localPosition.y - m_ParentStarPosY;
                m_Index = (int)(m_CurPosY / m_SpaceBetween);
                m_Surplus = m_CurPosY % m_SpaceBetween;
                if ((m_Surplus >= (m_SpaceBetween / 3) && m_Index > 0) || (m_Index < 0 && -m_Surplus >= (m_SpaceBetween / 3)))
                {
                    m_Index += (m_Index / Mathf.Abs(m_Index));
                }
                else if (m_Index == 0)
                {
                    if ((m_CurPosY > 0 && m_CurPosY >= (m_SpaceBetween / 3)) || (m_CurPosY < 0 && -m_CurPosY >= (m_SpaceBetween / 3)))
                    {
                        m_Index += (int)(m_CurPosY / Mathf.Abs(m_CurPosY));
                    }
                }
            }).setOnUpdate((float f) =>
            {
                ContentObj.localPosition = Vector3.Lerp(m_StartPos, new Vector3(ContentObj.localPosition.x, m_Index * m_SpaceBetween + m_ParentStarPosY, ContentObj.localPosition.z), f);
            });
        });
    }

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

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

    /// <summary>
    /// 碟片尺寸过渡
    /// </summary>
    void ChanageItemScale()
    {
        for (int i = 0; i < itemList.Count; i++)
        {
            if (itemList[i].transform.position.y < SingBox.transform.position.y + m_UpRange && itemList[i].transform.position.y > SingBox.transform.position.y - m_UpRange)
            {
                float m_addSca = m_UpRange - Math.Abs(itemList[i].transform.position.y - SingBox.transform.position.y);
                itemList[i].transform.localScale = Vector3.one + new Vector3(m_addSca, m_addSca, m_addSca);

                if (m_addSca >= (m_UpRange - 0.3f))//&& i != m_LastIndex
                {
                    if (SelectItem != i)
                    {
                        SelectItem = i;                                                     //得到Scale最大的碟片序号
                        SelectDic = itemList[i].transform.GetComponent<DicItem>();          //得到Scale最大的碟片信息
                    }
                }
            }
            else
            {
                itemList[i].transform.transform.localScale = Vector3.one;
            }
        }
    }

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

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

    //List<DicItem> sortList(int _ChanageIndx, List<DicItem> _list)
    //{
    //    List<DicItem> temp = new List<DicItem>();
    //    for (int i = 0; i < _list.Count; i++)
    //    {
    //        if (_ChanageIndx < 0)
    //            temp[i] = _list[(i + 1) % _list.Count];
    //        else
    //            temp[i] = _list[(_list.Count - 1 - i) % _list.Count];
    //    }
    //    return temp;
    //}
}

在上下AddChild()的拓
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public static partial class Extensions{

    public static T[] AddChild<T>(this Transform trans,GameObject t,int count,bool isReset = false)where T:MonoBehaviour
    {
        //获取所有子物体
        T[] children = trans.GetComponentsInChildren<T>(true);
        

        //子物体的数量少于要求的
        if (children.Length < count)
        {
            //要补充创建的数量
            int createCount = count - children.Length;

            for(int i = 0; i < createCount; i++)
            {
                 //实例化的对象
                GameObject go = GameObject.Instantiate(t);
                //设置父物体
                go.transform.SetParent(trans);
                //设置初值
                go.transform.localScale = Vector3.one;
                go.transform.localPosition = Vector3.zero;
            }
        }
        children = trans.GetComponentsInChildren<T>(true);
        int cur = 0;
        for(int i = 0; i < children.Length; i++)
        {
            //获取子物体
            T child = children[i];
            child.transform.SetParent(trans);
            child.transform.localScale = Vector3.one;
            child.transform.localPosition = Vector3.zero;
            //如果索引小于物体总数
            if (cur < count)
                //激活子物体
                child.gameObject.SetActive(true);
            else
                //失活子物体
                child.gameObject.SetActive(false);
            //索引++
            cur++;
        }
        //返回数组
        return trans.GetComponentsInChildren<T>()
}
    /// <summary>
    /// 数组转list
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="arr"></param>
    /// <returns></returns>
    public static List<T> ToList<T>(this T[] arr)
    {
        List<T> list = new List<T>();
        for (int i = 0; i < arr.Length; i++)
        {
            list.Add(arr[i]);
        }
        return list;
    }

}
组件面板参数设置

能力有限,只是抱着分享和记录并学习的想法上传了,有不妥的地方,见谅。

(一直没有补上效果图。。。隔一年了再来补上2018.6.23)




猜你喜欢

转载自blog.csdn.net/sam_one/article/details/60467911