为了实现带阻尼滑动居中,在网上查了蛮多资料,但是感觉都不怎么好用,只能自己花时间摸索了。实时拖拽就利用了UGUI的ScrollView实现了,回弹和阻尼居中用了LeanTween(我现在项目里都在用这个,所以直接拿来用了,可以用自己写其他的代替),仔细看看里面有很多地方是可以优化的,比如,我这需要判断列表里对象的奇偶性。。。大概的思路就是这样,工作经验实在有限。差点忘了,里面还有选中区域内放大功能。
脚本我就挂在ScrollView上
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
public class MusicScrollView : MonoBehaviour, IEndDragHandler, IBeginDragHandler
{
LTDescr lt;//LeanTween
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; //父节点
//[UI设置参数]
private float m_inertiaTime = 0f; //惯性作用时间
private float m_BackTime = 0.3f; //会弹时间
private float m_startDecelert = 0.8f;//初始惯性加速度
private float m_UpRange = 0.4f; //放大检测范围及Scale增量
float m_SpaceBetween; //设置的碟片间距
float m_ParentStarPosY; //Content初始Y位置
float m_CurPosY; //Content相对Y位置(0为参考)
float m_ItemHight; //碟片高度
int m_Index = 0; //Y位置与碟片(高度+间距)的整倍数
float m_Surplus = 0; //Y位置与碟片(高度+间距)的整倍后剩余
Vector3 m_StartPos; //记录每次需要居中前的Content位置
void Awake()
{
_instance = this;
scrollRect = GetComponent<ScrollRect>();
ContentObj = scrollRect.content;
}
void OnEnable()
{
}
// Use this for initialization
void Start()
{
m_ItemHight = Math.Abs(2 * ItemObj.transform.GetComponent<RectTransform>().rect.y);//sizeDelta.y获取的是子对象UI的Height(此处的方法会根据锚点不同而修改)
m_SpaceBetween = ContentObj.GetComponent<GridLayoutGroup>().spacing.y + m_ItemHight;
//Debug.Log(m_ItemHight);
}
void Init()
{
if (ContentObj.childCount % 2 == 0)//判断子对象的奇偶
{
m_ParentStarPosY = -(m_SpaceBetween / 2);
ContentObj.localPosition = new Vector3(ContentObj.localPosition.x, m_ParentStarPosY, ContentObj.localPosition.z);
}
m_ParentStarPosY = ContentObj.localPosition.y;
}
// Update is called once per frame
void Update()
{
//Debug.Log(ParentList.localPosition + "____" + ParentList.position);
//Debug.Log(ContentObj.GetChild(4).position);
ChanageItemScale();
}
/// <summary>
/// 更新列表内容
/// </summary>
/// <param name="Rr">对象</param>
public void RefreshMusicList(List<ResResut> Rr)
{
gameObject.SetActive(true);
DicItem[] itemList = ContentObj.AddChild<DicItem>(ItemObj.gameObject, Rr.Count);
for (int i = 0; i < itemList.Length; i++)
{
if (Rr[i].ResType == 1)
itemList[i].Init(Rr[i],i%3+6);//
}
Init();//更新列表位置
}
/// <summary>
/// Item定位
/// </summary>
public void LocateItem()
{
//Debug.Log(m_Index + "========Index");
//Debug.Log(m_CurPosY + "___sp___" + m_Surplus + "___cur__" + m_Index * m_SpaceBetween + m_ParentStarPosY);
lt = LeanTween.value(0, 1, m_inertiaTime).setOnStart(() =>
{
scrollRect.decelerationRate = 0.6f;
}).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));
//Debug.Log(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));
}
}
//Debug.Log(m_Index + "___wai");
}).setOnUpdate((float f) =>
{
ContentObj.localPosition = Vector3.Lerp(m_StartPos, new Vector3(ContentObj.localPosition.x, m_Index * m_SpaceBetween + m_ParentStarPosY, ContentObj.localPosition.z), f);
//Debug.Log(f+"___Scale_F_____+ Pos"+ ContentObj.localPosition);
});
});
}
void IEndDragHandler.OnEndDrag(PointerEventData eventData) //结束拖拽
{
//Debug.Log("UP");
scrollRect.OnEndDrag(eventData);
m_inertiaTime = Mathf.Clamp01(Math.Abs(eventData.delta.y * 0.008f));
LocateItem();
}
public void OnBeginDrag(PointerEventData eventData) //开始拖拽
{
//Debug.Log("New ");
if (lt != null)
lt.reset();
//scrollRect.OnEndDrag(eventData);
//((IBeginDragHandler)Instance).OnBeginDrag(eventData);
//Debug.Log(eventData.delta.y + "____start");
}
/// <summary>
/// 碟片尺寸过渡
/// </summary>
void ChanageItemScale()
{
for (int i = 0; i < ContentObj.childCount; i++)
{
if (ContentObj.GetChild(i).position.y < SingBox.transform.position.y+ m_UpRange && ContentObj.GetChild(i).position.y > SingBox.transform.position.y- m_UpRange)
{
float m_addSca = m_UpRange - Math.Abs(ContentObj.GetChild(i).position.y - SingBox.transform.position.y);
ContentObj.GetChild(i).transform.localScale = Vector3.one + new Vector3(m_addSca, m_addSca, m_addSca);
}
else
{
ContentObj.GetChild(i).transform.localScale = Vector3.one;
}
}
}
}
下面是面板上的设置截图