这篇文章主要为大家详细介绍了Unity实现仿3D轮转图,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
本文实例为大家分享了Unity实现仿3D轮转图效果的具体代码,供大家参考,具体内容如下
一、效果演示
二、实现思路
——获取位置:可以将每个item的运行轨迹看作一个椭圆,分为四段进行观察,四个黑点视为四个item,观察四个黑点的位置,比例值为0.125和0.375的位置相同,比例值为0.625和0.875的位置相同,比例值为0.375和0.625的位置相反,可得结论
[0,0.25]:轨迹总长度*当前比例值
(0.25,0.5]:轨迹总长度 * (0.5 - 当前比例值)
(0.5,0.75]:轨迹总长度 * (0.5 - 当前比例值)
(0.75,1]:轨迹总长度 * (当前比例值 - 1)
——获取缩放值:可以将每个item的运行轨迹看作一个椭圆,分为四段进行观察,四个黑点视为四个item,观察四个黑点的位置,比例值为0时缩放值应为最大,比例值为0.5时缩放值应为最小,可得结论
[0-0.5]:缩放最大值 - 比例值 * (缩放最大值 - 缩放最小值) * 2
(0.5-1]:缩放最大值 - (1 - 比例值) * (缩放最大值 - 缩放最小值) * 2
——获取层级:使用UGUI的自然层级进行排序(越靠下越后渲染),拷贝一份列表item数据列表按照缩放值从小到大的顺序排序,再通过SetSiblingIndex依次设置层级
三、使用
——常规使用
SetData:传入item预制体和列表中item个数
OnSetItem:绑定设置item的方法
SetList:设置列表的显示
using UnityEngine; using UnityEngine.UI; public class Test : MonoBehaviour { public GameObject prefab; public Rotary3DList rotary3DList; private void Start() { rotary3DList.SetData(prefab, 5); rotary3DList.OnSetItem = SetItem; rotary3DList.SetList(); } void SetItem(Rotary3DList.ListItemData listItemData) { listItemData.go.GetComponent().txt = listItemData.index.ToString(); } }
——MoveToIndex:移动到某一个下标位置,isScroll表示是否滑动到指定位置
——GetListItemData:获取到某个下标的item数据
——CenterIndex:当前中心点item下标
四、代码实现
using System.Collections.Generic; using UnityEngine; using System; using UnityEngine.UI; using UnityEngine.EventSystems; using System.Linq; ////// 仿3D轮转图组件 /// [AddComponentMenu("LFramework/UI/Rotary3DList", 50)] [RequireComponent(typeof(Image))] public class Rotary3DList : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler { ////// 列表item数据 /// public class ListItemData { public int index; public GameObject go; public float targetValue;//目标位置长度值 public float tempValue;//临时位置长度值(每次拖拽结束后才更新数值) } ////// 轮转类型 /// public enum RotaryType { Horizontal, Vertical, } public RotaryType rotaryType;//轮转类型 public float spacing;//间隔 public float maxScale = 1;//最大缩放值 public float minScale = 0.5f;//最小缩放值 public float t = 0.1f;//缓动插值 public ActionOnSetItem;//设置item public Action OnDragBegin;//拖拽开始 public Action OnDragging;//拖拽中 public Action OnDragEnd;//拖拽结束 //中心item下标 public int CenterIndex { get { return GetCenterItemIndex(); } } int m_ItemCount;//列表item总数量 float m_TotalValue;//总长度值 float m_DeltaValue;//长度值增量 GameObject m_Prefab; RectTransform m_ItemContainer; List m_ListItemDataList = new List (); bool m_InDrag; float m_BeginPos; List m_InitValueList = new List ();//初始每个item的位置长度值 /// /// 设置数据 /// public void SetData(GameObject prefab, int itemCount) { m_ItemContainer = GetComponent(); m_ItemCount = itemCount; m_Prefab = prefab; m_DeltaValue = rotaryType == RotaryType.Horizontal ? (spacing + m_Prefab.GetComponent ().rect.width) : (spacing + m_Prefab.GetComponent ().rect.height); m_TotalValue = m_DeltaValue * m_ItemCount; InitData(); } /// /// 初始化数据 /// void InitData() { float tempValue = 0; for (int i = 0; i/// 设置列表 /// public void SetList() { foreach (var data in m_ListItemDataList) { OnSetItem?.Invoke(data); } UpdateItem(true); } /// /// 移动到某个下标位置 /// public void MoveToIndex(int index, bool isScroll = true) { if (index <0 || index>= m_ItemCount) { Debug.LogError("下标超出范围,index : " + index); return; } int indexOffset = CenterIndex - index; foreach (var data in m_ListItemDataList) { float tempValue = data.tempValue + m_DeltaValue * indexOffset <0 ? data.tempvalue + m_deltavalue * indexoffset m_totalvalue : indexoffset; float targetvalue=tempValue % m_totalvalue; data.targetvalue=targetValue; targetvalue; } updateitem(!isscroll); public void onbegindrag(pointereventdata eventdata) { m_indrag=true; m_beginpos=rotaryType> 0) { foreach (var data in m_ListItemDataList) { float tempValue = (data.tempValue + offset) % m_TotalValue; data.targetValue = tempValue; } } else if (offset <0) { foreach (var data in m_ListItemDataList) { float tempValue = data.tempValue + offset <0 ? m_totalvalue - mathf.abs(data.tempvalue + offset) % : (data.tempvalue m_totalvalue; data.targetvalue=tempValue; } public void onenddrag(pointereventdata eventdata) { m_indrag=false; ondragend?.invoke(eventdata); foreach (var data in m_listitemdatalist) float nearlyvalue=GetNearlyValue(data.targetValue); nearlyvalue; data.tempvalue=nearlyValue; private update() updateitem(false);> /// 更新item /// void UpdateItem(bool isForce) { //拖拽中-实时更新 if (m_InDrag) { foreach (var data in m_ListItemDataList) { float ratio = data.targetValue / m_TotalValue; //更新位置 float pos = GetPos(ratio); Vector2 targetPos = rotaryType == RotaryType.Horizontal ? new Vector2(pos, 0) : new Vector2(0, pos); data.go.transform.localPosition = targetPos; //更新缩放值 float scale = GetScale(ratio); Vector2 targetScale = Vector3.one * scale; data.go.transform.localScale = targetScale; } } //非拖拽中-缓动更新 else { foreach (var data in m_ListItemDataList) { float ratio = data.targetValue / m_TotalValue; //更新位置 float pos = GetPos(ratio); Vector2 targetPos = rotaryType == RotaryType.Horizontal ? new Vector2(pos, 0) : new Vector2(0, pos); float targetPosOffset = rotaryType == RotaryType.Horizontal ? data.go.transform.localPosition.x - targetPos.x : data.go.transform.localPosition.y - targetPos.y; data.go.transform.localPosition = Vector2.Lerp(data.go.transform.localPosition, targetPos, isForce ? 1 : t); if (Mathf.Abs(targetPosOffset) <= 0.01f) { data.go.transform.localPosition = targetPos; } //更新缩放值 float scale = GetScale(ratio); Vector2 targetScale = Vector3.one * scale; float targetScaleOffset = data.go.transform.localScale.x - targetScale.x; data.go.transform.localScale = Vector2.Lerp(data.go.transform.localScale, targetScale, isForce ? 1 : t); if (Mathf.Abs(targetScaleOffset) <= 0.01f) { data.go.transform.localScale = targetScale; } } } //更新层级 var listItemDataList = m_ListItemDataList.OrderBy(data => GetScale(data.targetValue / m_TotalValue)).ToList(); for (int i = 0; i/// 得到位置 /// float GetPos(float ratio) { if (ratio <0 && ratio> 1) { Debug.LogError("比例值错误,比例值必须为[0-1],ratio : " + ratio); return 0; } if (ratio >= 0 && ratio <= 0.25f) { return m_TotalValue * ratio; } else if (ratio > 0.25f && ratio <= 0.75f) { return m_TotalValue * (0.5f - ratio); } else { return m_TotalValue * (ratio - 1); } } /// /// 得到缩放值 /// float GetScale(float ratio) { if (ratio <0 && ratio> 1) { Debug.LogError("比例值错误,比例值必须为[0-1],ratio : " + ratio); return 0; } float v = (maxScale - minScale) * 2; if (ratio >= 0 && ratio <= 0.5f) { return maxScale - ratio * v; } else { return maxScale - (1 - ratio) * v; } } ////// 得到距离最近的位置长度值 /// float GetNearlyValue(float curValue) { float minDis = Mathf.Abs(curValue - m_InitValueList.First()); float nearlyValue = m_InitValueList.First(); foreach (var value in m_InitValueList) { float tempDis = Mathf.Abs(curValue - value); if (tempDis/// 得到中心item的下标 /// int GetCenterItemIndex() { int index = 0; float minDis = Mathf.Min(Mathf.Abs(m_ListItemDataList[0].targetValue - m_InitValueList.First()), Mathf.Abs(m_ListItemDataList[0].targetValue - m_InitValueList.Last())); foreach (var data in m_ListItemDataList) { float tempDis = Mathf.Min(Mathf.Abs(data.targetValue - m_InitValueList.First()), Mathf.Abs(data.targetValue - m_InitValueList.Last())); if (tempDis /// 得到列表item数据 /// public ListItemData GetListItemData(int index) { if (index <0 || index>= m_ItemCount) { Debug.LogError("下标超出范围,index : " + index); return null; } return m_ListItemDataList[index]; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持0133技术站。
以上就是Unity实现仿3D轮转图效果的详细内容,更多请关注0133技术站其它相关文章!