在项目中需要一个环形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 framevoid Update(){}
}