在项目中需要一个环形UI并且循环往复的效果,这个方法思路为提前预设好位置,让UI根据坐标预设的移动,然后使用mask遮罩达到循环往复效果的目的。
下图分别分为了三个列表
第一个列表poslist是提前预设的位置
第二个列表为背景暂时不用看
第三个列表btnlist为实际的移动UI
脚本上首先把路径放入,路径要比实际UI多两个是为了制作进入退出的动画效果,路径可以是空物体,实际作用就是为了定位移动。
第二个列表就为实际的操作UI
中心点设置是根据路径列表长度,如果是2那就是路径列表第[2]个,根据自己的列表调整
剩下两个列表为文字显示使用,方便显示各个btn要显示的名称
以下就是具体实现代码,代码不复杂理解一下就能愉快的玩耍了
using Cysharp.Threading.Tasks;
using DG.Tweening;
using QFramework;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Cysharp.Threading.Tasks.CompilerServices;
using System.Threading;
using TMPro; // 关键命名空间
public class LoopUI : MonoBehaviour
{
public List<RectTransform> posList = new List<RectTransform>();
public List<RectTransform> itemlist = new List<RectTransform>();
bool is_是否处于动画 = true;
public int index_中心点 = 2;
public CanvasGroup BG_背景动画;
public List< TextMeshProUGUI> texts =new List<TextMeshProUGUI>();
public List<string> btn_names=new List<string>();
void Start()
{
Ins_初始化item坐标();
}
void Ins_初始化item坐标()
{
for (int i = 0; i < itemlist.Count; i++)//第一步先吧 需要移动的放到相应的位置
{
itemlist[i].anchoredPosition = posList[i + 1].anchoredPosition;
var aa = itemlist[i];
itemlist[i].GetComponent<Button>().onClick.AddListener(() => SetPos(aa));
}
//实例化第一个和最后一个用于 进行动画过渡
//把第一个的实力放在最下面,取名为1因为这是实例化列表中的第一个
var ins = Instantiate(itemlist[0], posList[posList.Count - 1].position, posList[posList.Count - 1].rotation, itemlist[0].parent);
// ins.name = "1";
//把第二个的示例放在最上面 取名为6因为这是实例化列表中的最后一个
var ins2 = Instantiate(itemlist[itemlist.Count - 1], posList[0].position, posList[0].rotation, itemlist[itemlist.Count - 1].parent);
// ins2.name = "6";
//位置放过后 路径排序为123456 UI实际排序为234516,因为实际ui就只有2345,1和6都是实例化生成进行动画过渡的,所以5后面跟1进行动画衔接
itemlist.Insert(0,ins);
ins.GetComponent<Button>().onClick.AddListener(() => SetPos(ins));
itemlist.Add(ins2);
ins2.GetComponent<Button>().onClick.AddListener(() => SetPos(ins2));
for (int i = 0; i < texts.Count; i++)
{
texts[i].text = btn_names[i];
}
}
async UniTask UImove(float chat, bool istrue)
{
if (istrue)
{
//移动过后删除隐藏起来的并移除
Destroy(itemlist[0].gameObject);
Destroy(itemlist[itemlist.Count - 1].gameObject);
itemlist.Remove(itemlist[0]);
itemlist.Remove(itemlist[itemlist.Count - 1]);
//生成新的第一与最后一位,进行下一次动画移动
var ins = Instantiate(itemlist[0], posList[posList.Count - 1].position, posList[posList.Count - 1].rotation, itemlist[0].parent);
var ins2 = Instantiate(itemlist[itemlist.Count - 1], posList[0].position, posList[0].rotation, itemlist[itemlist.Count - 1].parent);
//生成的第一个放到倒数第二个 最后一个还是放在最后
itemlist.Add(ins);
ins.GetComponent<Button>().onClick.AddListener(() => SetPos(ins));
itemlist.Add(ins2);
ins2.GetComponent<Button>().onClick.AddListener(() => SetPos(ins2));
var s = btn_names[0];
btn_names.Remove(btn_names[0]);
btn_names.Add(s);
for (int i = 0; i < texts.Count; i++)
{
texts[i].text = btn_names[i];
}
for (int x = 0; x < itemlist.Count; x++)
{
itemlist[x].DOAnchorPos(posList[x].anchoredPosition, chat).SetEase(Ease.Linear).ToUniTask().Forget();
}
await UniTaskManager.Instance.DelayedOperation(chat, () =>
{
is_是否处于动画 = true;
});
}
else
{
Destroy(itemlist[0].gameObject);
Destroy(itemlist[itemlist.Count - 1].gameObject);
itemlist.Remove(itemlist[0]);
itemlist.Remove(itemlist[itemlist.Count - 1]);
//生成新的第一与最后一位,进行下一次动画移动
var ins = Instantiate(itemlist[0], posList[posList.Count - 1].position, posList[posList.Count - 1].rotation, itemlist[0].parent);
var ins2 = Instantiate(itemlist[itemlist.Count - 1], posList[0].position, posList[0].rotation, itemlist[itemlist.Count - 1].parent);
//生成的第一个放到倒数第二个 最后一个还是放在最后
itemlist.Insert(0, ins2);
ins2.GetComponent<Button>().onClick.AddListener(() => SetPos(ins2));
itemlist.Insert(0, ins);
ins.GetComponent<Button>().onClick.AddListener(() => SetPos(ins));
//把按钮名称排序
var s = btn_names[btn_names.Count - 1];
btn_names.Remove(btn_names[btn_names.Count - 1]);
btn_names.Insert(0, s);
for (int i = 0; i < texts.Count; i++)
{
texts[i].text = btn_names[i];
}
for (int x = 0; x < itemlist.Count; x++)
{
itemlist[x].DOAnchorPos(posList[x].anchoredPosition, chat).SetEase(Ease.Linear).ToUniTask().Forget();
}
await UniTaskManager.Instance.DelayedOperation(chat, () => { is_是否处于动画 = true;});
}
}
private async void SetPos(RectTransform a)
{
if (!is_是否处于动画) return;
is_是否处于动画 = false;
//首先获取当前在列表中属于第几位
var t = itemlist.IndexOf(a);
//获取距离中心点差多少
float chat = t - index_中心点;
if (chat > 0)//算算当前要移动几下
{
BG_背景动画.DOFade(0, 0.5f).SetEase(Ease.Linear).OnComplete(() => {
BG_背景动画.DOFade(1, 0.5f).SetEase(Ease.Linear); }).ToUniTask().Forget();
for (int i = 0; i < chat; i++)
{
await UImove(1f / chat, true);
}
}
else if (chat < 0)
{
BG_背景动画.DOFade(0, 0.5f).SetEase(Ease.Linear).OnComplete(() => {
BG_背景动画.DOFade(1, 0.5f).SetEase(Ease.Linear); }).ToUniTask().Forget();
for (int i = 0; i > chat; i--)
{
await UImove(1f / Mathf.Abs(chat), false);
}
}
else { is_是否处于动画 = true; }
}
// Update is called once per frame
void Update()
{
}
}