要做一个轮播功能,以前也有写,但是感觉不通用,百度找的又有各种各样的问题,所以自己整理了一个
目前只支持左右一位位移,没有自己去写缓动,用的DoTween
暂定1.0版本吧,后面会继续优化
其实就是列表存储,后面根据目标位置信息,去做位移和缩放等行为
直接上代码吧:
/*******************************************************************************
* 版本声明:v1.0.0
* 类 名 称:UIRotationManager
* 创建日期:2020-05-19 15:52:49
* 作者名称:末零
* 功能描述:UGUI轮播
* 修改记录:
* v1.0.0 完成左右一位的位移(多位目前测试会有bug)
* 当前全部显示,不能选择轮播物体显示个数
*
******************************************************************************/
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
namespace LastZero
{
/// <summary>
/// 状态枚举
/// </summary>
public enum RotationState
{
Rotating,
Stop
}
/// <summary>
/// 轮播
/// </summary>
public class UIRotationManager : MonoBehaviour
{
public int indexCenter = 0;//初始时,位于中间位置的对象ID
public float cellWidth = 100;//宽度
public float scaleMultiple = 1;//缩放倍数
public float speed = 5;//轮播速度
private List<UIRotationItem> items = new List<UIRotationItem>();//所有子物体(要轮播的)
private List<int> relativePosition = new List<int>();//相对位置
private int indexHalf;//轮播对象数量的中值
private List<int> order = new List<int>();//顺序
private RotationState state = RotationState.Stop;//状态
private void Awake()
{
items.AddRange(transform.GetComponentsInChildren<UIRotationItem>());
}
private void Start()
{
Init();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
DoRotateItems(1);
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
DoRotateItems(-1);
}
}
/// <summary>
/// 初始化
/// </summary>
private void Init()
{
indexHalf = (items.Count - 1) / 2;
for (int i = 0; i < items.Count; i++)
{
int target = i - indexHalf + indexCenter;
target = target < 0 ? target + items.Count : target >= items.Count ? target - items.Count : target;
items[i] = transform.GetChild(target).GetComponent<UIRotationItem>();
relativePosition.Add(i - indexHalf);
}
DoRotateItems();
}
/// <summary>
/// 获取当前状态
/// </summary>
/// <returns></returns>
public RotationState GetState()
{
return state;
}
/// <summary>
/// 轮播
/// </summary>
/// <param name="value"></param>
public void DoRotateItems(int value = 0)
{
if (state == RotationState.Rotating) return;
order.Clear();
for (int i = 0; i < items.Count; i++)
{
int target = i + value;
if (target < 0)
{
target += items.Count;
}
else if (target >= items.Count)
{
target -= items.Count;
}
order.Add(target);
if ((target == 0 && value > 0) || (target == items.Count - 1 && value < 0))
{
int indexI = i;
int indexTarget = target;
items[i].transform.DOScale(0.01f, Mathf.Abs(value) / speed * 0.5f).OnComplete(() =>
{
items[indexI].LocalPositionX = relativePosition[indexTarget] * cellWidth * Mathf.Pow(scaleMultiple, Mathf.Abs(relativePosition[indexTarget]));
items[indexI].transform.DOScale(Mathf.Pow(scaleMultiple, Mathf.Abs(relativePosition[indexTarget])), Mathf.Abs(value) / speed * 0.5f).SetEase(Ease.Linear);
});
}
else
{
items[i].transform.DOLocalMoveX(relativePosition[target] * cellWidth * Mathf.Pow(scaleMultiple, Mathf.Abs(relativePosition[target])), Mathf.Abs(value) / speed).SetEase(Ease.Linear);
items[i].transform.DOScale(Mathf.Pow(scaleMultiple, Mathf.Abs(relativePosition[target])), Mathf.Abs(value) / speed).OnComplete(() =>
{
state = RotationState.Stop;
}).SetEase(Ease.Linear);
}
}
StartCoroutine(CallBack(Mathf.Abs(value)));
state = RotationState.Rotating;
}
/// <summary>
/// 回调(单次轮播进行到一半时,重置List、改变SiblingIndex)
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
private System.Collections.IEnumerator CallBack(int time)
{
yield return new WaitForSeconds(time * 0.5f / speed);
UIRotationItem[] newItems = new UIRotationItem[items.Count];
for (int i = 0; i < items.Count; i++)
{
newItems[order[i]] = items[i];
}
items.Clear();
items.AddRange(newItems);
ChangeSiblingIndex();
}
/// <summary>
/// 改变SiblingIndex
/// </summary>
private void ChangeSiblingIndex()
{
for (int i = 0; i < items.Count; i++)
{
int index;
index = relativePosition[i]>=0? items.Count - 1 - relativePosition[i] * 2 : items.Count - 1 + relativePosition[i] * 2 + 1;
items[i].SiblingIndex = index;
}
}
}
}
Item其实只是提供了几个属性,没做什么实际功能
public float LocalPositionX
{
get { return transform.localPosition.x; }
set { transform.localPosition = new Vector3(value, transform.localPosition.y, transform.localPosition.z); }
}
public float LocalScale
{
get { return transform.localScale.x; }
set { transform.localScale = Vector3.one * value; }
}
public int SiblingIndex
{
get { return transform.GetSiblingIndex(); }
set { transform.SetSiblingIndex(value); }
}