前两天写的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)