using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;
/**
* LoopMover类用于管理循环移动的UI元素。
*/
public class LoopMover : MonoBehaviour
{
public List<RectTransform> items; // 存储需要循环移动的UI元素
public List<RectTransform> images; // 存储与items对应的背景图片
public float initWidth = 20f; // 初始化宽度
public float startTime = 0; // 开始时间
float cumulativeOffset = 0; // 累积偏移量
public float[] times = new float[4]; // 每个元素显示的时间
public float speed; // 移动速度
/**
* Awake函数在对象唤醒时调用,用于初始化图片大小和位置。
*/
private void Awake()
{
if (images == null || images.Count == 0) return;
speed = images[0].sizeDelta.x / times[0]; // 计算移动速度
InitializeImageSizes(); // 初始化图片大小
float totalx = 0;
float totalWidth = GetTotalWidth(); // 计算总宽度
// 设置每个元素的初始位置
for (int i = items.Count - 1; i >= 0; i--)
{
RectTransform item = items[i];
item.anchoredPosition = new Vector2(-(startTime * speed) + GetWidthWithoutImage(i), 0);
// 调整元素位置以避免重叠
if (item.anchoredPosition.x < 0 && item.anchoredPosition.x > -images[i].sizeDelta.x)
{
cumulativeOffset = item.anchoredPosition.x;
}
if (item.anchoredPosition.x <= -images[i].sizeDelta.x)
{
totalx += images[i].sizeDelta.x;
item.anchoredPosition = new Vector2(totalWidth - totalx - Mathf.Abs(cumulativeOffset), 0);
}
}
}
/**
* InitializeImageSizes函数用于设置每个背景图片的大小。
*/
private void InitializeImageSizes()
{
for (int i = 0; i < images.Count; i++)
{
images[i].sizeDelta = new Vector2(times[i] * initWidth, 70); // 根据显示时间设置图片大小
}
}
/**
* Start函数在对象开始运行时调用,用于设置元素的动画效果。
*/
void Start()
{
for (int i = 0; i < items.Count; i++)
{
RectTransform item = items[i];
RectTransform image = images[i];
int index = i;
float newTime = (item.anchoredPosition.x + image.sizeDelta.x) / speed;
// 设置元素移动到初始位置的动画,并在到达后循环移动
item.DOAnchorPosX(-image.sizeDelta.x, newTime).SetEase((Ease.Linear)).OnComplete(() =>
{
item.anchoredPosition = new Vector2(GetWidth(index), 0);
item.DOAnchorPosX(-image.sizeDelta.x, GetTime(items.Count)).SetEase((Ease.Linear)).SetLoops(-1);
});
}
}
/**
* GetTotalWidth函数计算并返回所有背景图片的总宽度。
*
* @return float 所有背景图片的总宽度。
*/
float GetTotalWidth()
{
float width = 0;
for (int i = 0; i < images.Count; i++)
{
width += images[i].sizeDelta.x;
}
return width;
}
/**
* GetWidth函数根据指定索引计算并返回除该索引对应元素外的所有元素宽度之和。
*
* @param idx 指定元素的索引。
* @return float 除指定元素外的所有元素宽度之和。
*/
float GetWidth(int idx)
{
float width = 0;
for (int i = 0; i < images.Count; i++)
{
if (idx != i)
{
width += images[i].sizeDelta.x;
}
}
return width;
}
/**
* GetWidthWithoutImage函数根据指定索引计算并返回该索引之前的所有元素宽度之和。
*
* @param idx 指定元素的索引。
* @return float 该索引之前的所有元素宽度之和。
*/
float GetWidthWithoutImage(int idx)
{
float width = 0;
for (int i = 0; i < images.Count; i++)
{
if (idx > i)
{
width += images[i].sizeDelta.x;
}
}
return width;
}
/**
* GetTime函数根据指定索引计算并返回该索引对应的时间。
*
* @param idx 指定元素的索引。
* @return float 指定元素的显示时间。
*/
float GetTime(int idx)
{
float time = 0;
for (int i = 0; i < times.Length; i++)
{
if (i <= idx)
{
time += times[i];
}
}
return time;
}
}
实现多个RectTransform首尾无缝衔接无尽循环,可以通过自定义开始时间计算出当前开始的位置,支持每个RectTransform自定义大小。