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