Unity 通用UI界面逻辑总结

打印 上一主题 下一主题

主题 1003|帖子 1003|积分 3009

概述

在游戏开发中,常常会遇到一些通用的界面逻辑,它不论在什么范例的游戏中都会出现。为了避免重复造轮子,本文总结并提供了一些常用UI界面的实现逻辑。希望可以帮助大家快速开发通用界面模块,也可以在次底子上举行扩展修改,以适应你项目标需求。
工程链接:GitCode - 全球开发者的开源社区,开源代码托管平台

二次确认界面


  1. using UnityEngine;
  2. using UnityEngine.Events;
  3. using UnityEngine.UI;
  4. public class ConfirmDialog : MonoBehaviour
  5. {
  6.     private Text txt_title;
  7.     private Text txt_content;
  8.     private Button btn_Yes;
  9.     private Button btn_No;
  10.     void Start()
  11.     {
  12.         var root = gameObject.transform;
  13.         txt_title = root.Find("txt_Title").GetComponent<Text>();
  14.         txt_content = root.Find("txt_Content").GetComponent<Text>();
  15.         btn_Yes = root.Find("btn/btn_Yes").GetComponent<Button>();
  16.         btn_No = root.Find("btn/btn_No").GetComponent<Button>();
  17.         txt_title.text = "提示";
  18.         
  19.         //测试代码
  20.         InitDialog("好好学习,天天向上!",
  21.             () => {Debug.Log("Yes"); },
  22.             () => {Debug.Log("No"); });
  23.     }
  24.     /// <summary>
  25.     /// 重载一:使用默认标题 “提示”
  26.     /// </summary>
  27.     /// <param name="content">需要确认的内容</param>
  28.     /// <param name="yesAction">确认按钮回调</param>
  29.     /// <param name="noAction">取消按钮回调</param>
  30.     public void InitDialog(string content, UnityAction yesAction = null, UnityAction noAction = null)
  31.     {
  32.         txt_title.text = "提示";
  33.         CoreLogic(content, yesAction, noAction);
  34.     }
  35.     /// <summary>
  36.     /// 重载一:使用自定义标题
  37.     /// </summary>
  38.     /// <param name="title">自定义标题</param>
  39.     /// <param name="content">需要确认的内容</param>
  40.     /// <param name="yesAction">确认按钮回调</param>
  41.     /// <param name="noAction">取消按钮回调</param>
  42.     public void InitDialog(string title, string content, UnityAction yesAction = null, UnityAction noAction = null)
  43.     {
  44.         txt_title.text = title;
  45.         CoreLogic(content, yesAction, noAction);
  46.     }
  47.     //公共逻辑提取
  48.     private void CoreLogic(string content, UnityAction yesAction = null, UnityAction noAction = null)
  49.     {
  50.         txt_content.text = content;
  51.         BindBtnLogic(btn_Yes, yesAction);
  52.         BindBtnLogic(btn_No, noAction);
  53.         btn_Yes.gameObject.SetActive(yesAction != null);
  54.         btn_No.gameObject.SetActive(noAction != null);
  55.     }
  56.     //绑定按钮点击回调
  57.     private void BindBtnLogic(Button btn, UnityAction action)
  58.     {
  59.         btn.onClick.RemoveAllListeners();
  60.         if (action != null)
  61.         {
  62.             btn.onClick.AddListener(action);
  63.         }
  64.     }
  65. }
复制代码
切页标签


通过按钮来实现。固然使用Toggle也可以实现,但是在实际开发中会发现使用toggle不好控制选中变乱的触发和选中状态表现。通过按钮来自定义组件可以更好地控制逻辑的调用和标签的显示。
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEngine.Events;
  4. using UnityEngine.UI;
  5. class TabNode
  6. {
  7.     public int index;
  8.     public GameObject offBg;
  9.     public GameObject onBg;
  10.     public Text offTxt;
  11.     public Text onTxt;
  12.     public Button btn;
  13.     public UnityAction callback;
  14. }
  15. public class SwitchPageTab : MonoBehaviour
  16. {
  17.     public Transform tabRoot;//标签组的父节点
  18.     public GameObject tabObj;//标签页预制体模板
  19.     private int _selectIndex;//选中的标签页索引
  20.     private List<TabNode> _objList = new List<TabNode>();
  21.     private Dictionary<int, UnityAction> _callbackDic = new Dictionary<int, UnityAction>();
  22.    
  23.     private void Start()
  24.     {
  25.         _selectIndex = -1;
  26.         
  27.         InitCount(4);
  28.         BindSelectCallback(0, "背包", (() =>
  29.         {
  30.             Debug.Log("查看背包");
  31.         }));
  32.         BindSelectCallback(1, "英雄", (() =>
  33.         {
  34.             Debug.Log("查看英雄");
  35.         }));
  36.         BindSelectCallback(2, "商店", (() =>
  37.         {
  38.             Debug.Log("查看商店");
  39.         }));
  40.         BindSelectCallback(3, "活动", (() =>
  41.         {
  42.             Debug.Log("查看活动");
  43.         }));
  44.         
  45.         
  46.         OnSelectLogic(0);
  47.     }
  48.     /// <summary>
  49.     /// 初始化调用
  50.     /// </summary>
  51.     /// <param name="count">标签的数量</param>
  52.     public void InitCount(int count)
  53.     {
  54.         _objList.Clear();
  55.         ClearAllChild(tabRoot);
  56.         for (var i = 0; i < count; i++)
  57.         {
  58.             var obj = Instantiate(tabObj, tabRoot);
  59.             obj.SetActive(true);
  60.             var trans = obj.transform;
  61.             var node = new TabNode
  62.             {
  63.                 offTxt = trans.Find("btn/offBg/offTxt").GetComponent<Text>(),
  64.                 onTxt = trans.Find("btn/onBg/onTxt").GetComponent<Text>(),
  65.                 onBg = trans.Find("btn/onBg").gameObject,
  66.                 offBg = trans.Find("btn/offBg").gameObject,
  67.                 btn = trans.Find("btn").GetComponent<Button>(),
  68.             };
  69.             var index = i;
  70.             BindBtnLogic(node.btn, () =>
  71.             {
  72.                 OnSelectLogic(index);
  73.             });
  74.             _objList.Add(node);
  75.         }
  76.     }
  77.    
  78.     /// <summary>
  79.     /// 绑定指定页签索引的回调函数
  80.     /// </summary>
  81.     /// <param name="index">页签索引</param>
  82.     /// <param name="txt">页签问本</param>
  83.     /// <param name="callback">选中回调</param>
  84.     public void BindSelectCallback(int index,string txt,UnityAction callback)
  85.     {
  86.         if (_callbackDic.ContainsKey(index))
  87.         {
  88.             Debug.LogError("已经注册过了!");
  89.             return;
  90.         }
  91.         if (callback == null)
  92.         {
  93.             Debug.LogError("回调为空!");
  94.             return;
  95.         }
  96.         if (index < 0 || index > _objList.Count)
  97.         {
  98.             Debug.LogError("索引越界!");
  99.             return;
  100.         }
  101.         var node = _objList[index];
  102.         node.onTxt.text = txt;
  103.         node.offTxt.text = txt;
  104.         _callbackDic.Add(index,callback);
  105.     }
  106.    
  107.     /// <summary>
  108.     /// 调用指定索引对应的回调函数
  109.     /// </summary>
  110.     /// <param name="index"></param>
  111.     private void OnSelectLogic(int index)
  112.     {
  113.         if (index == _selectIndex)
  114.         {
  115.             return;
  116.         }
  117.         _selectIndex = index;
  118.         
  119.         var isExist = _callbackDic.TryGetValue(_selectIndex, out UnityAction callback);
  120.         if (isExist)
  121.         {
  122.             callback?.Invoke();
  123.             SetSelectStatus(index);
  124.         }
  125.     }
  126.    
  127.     /// <summary>
  128.     /// 控制指定页签的UI表现
  129.     /// </summary>
  130.     /// <param name="index"></param>
  131.     private void SetSelectStatus(int index)
  132.     {
  133.         var count = _objList.Count;
  134.         for (var i = 0; i < count; i++)
  135.         {
  136.             var isActive = index == i;
  137.             var node = _objList[i];
  138.             node.onBg.SetActive(isActive);
  139.             node.offBg.SetActive(!isActive);
  140.         }
  141.     }
  142.    
  143.     //清除指定父节点下的所有子物体
  144.     private void ClearAllChild(Transform parentRoot)
  145.     {
  146.         var childCount = parentRoot.childCount;
  147.         for (var i = childCount - 1; i >= 0; i--)
  148.         {
  149.             var child = parentRoot.GetChild(i);
  150.             DestroyImmediate(child.gameObject);
  151.         }
  152.     }
  153.     //绑定按钮点击回调
  154.     private void BindBtnLogic(Button btn, UnityAction action)
  155.     {
  156.         btn.onClick.RemoveAllListeners();
  157.         if (action != null)
  158.         {
  159.             btn.onClick.AddListener(action);
  160.         }
  161.     }
  162. }
复制代码

飘字提示

简易版本


  1. using UnityEngine;
  2. using UnityEngine.Pool;
  3. using DG.Tweening;
  4. using UnityEngine.UI;
  5. public class SimpleTip : MonoBehaviour
  6. {
  7.     //提示栏预制体
  8.     public GameObject tipObj;
  9.     //提示栏显示的父节点
  10.     public Transform tipRoot;
  11.     //对象池
  12.     private ObjectPool<GameObject> tipPool;
  13.     //飞行高度
  14.     private float flyHeight = 500;
  15.    
  16.     void Start()
  17.     {
  18.         InitTipPool();
  19.     }
  20.     void Update()
  21.     {
  22.         if (Input.GetKeyDown(KeyCode.Space))
  23.         {
  24.             ShowTip("货币不足!");
  25.         }
  26.     }
  27.     void ShowTip(string tipStr)
  28.     {
  29.         var obj = tipPool.Get();
  30.         var rectValue = obj.GetComponent<RectTransform>();
  31.         var group = obj.GetComponent<CanvasGroup>();
  32.         var txt = obj.transform.Find("txt").GetComponent<Text>();
  33.         txt.text = tipStr;
  34.         obj.SetActive(true);
  35.         group.alpha = 1;
  36.         ResetLocal(obj.transform);
  37.         rectValue.DOAnchorPosY(flyHeight, 1f).OnComplete(() =>
  38.         {
  39.             group.DOFade(0, 0.1f).OnComplete(() =>
  40.             {
  41.                 tipPool.Release(obj);
  42.             });
  43.         });
  44.     }
  45.    
  46.     //初始化对象池
  47.     void InitTipPool()
  48.     {
  49.         tipPool = new ObjectPool<GameObject>(() =>
  50.         {
  51.             //创建新对象调用
  52.             var obj = Instantiate(tipObj, tipRoot);
  53.             obj.SetActive(false);
  54.             return obj;
  55.         },
  56.         (go) =>
  57.         {
  58.             //获取对象调用
  59.             go.SetActive(true);
  60.             ResetLocal(go.transform);
  61.         },
  62.         (go) =>
  63.         {
  64.             // 在对象放回池子时调用
  65.             go.SetActive(false);
  66.             ResetLocal(go.transform);
  67.             go.transform.SetParent(tipRoot);
  68.         },
  69.         (go) =>
  70.         {
  71.             Destroy(go);
  72.         });
  73.     }
  74.    
  75.     //重置本地信息
  76.     void ResetLocal(Transform trans)
  77.     {
  78.         trans.localPosition = Vector3.zero;
  79.         trans.localEulerAngles = Vector3.zero;
  80.         trans.localScale = Vector3.one;
  81.     }
  82. }
复制代码
升级版本


  1. using System.Collections.Generic;
  2. using DG.Tweening;
  3. using UnityEngine;
  4. using UnityEngine.UI;
  5. using UnityEngine.Pool;
  6. public class GoodTip : MonoBehaviour
  7. {
  8.     //提示栏显示的父节点
  9.     public Transform root;
  10.     //提示栏模板预制体
  11.     public GameObject tipObj;
  12.     //对象池节点
  13.     public Transform objectPool;
  14.    
  15.     //最多显示的提示栏数量,超过就隐藏
  16.     private int limitCount = 5;
  17.     //提示栏之间的偏移
  18.     private float offset = 20;
  19.     //提示飞行高度
  20.     private float flyHeight = 100;
  21.     //提示栏生成数量,只用于逻辑运算
  22.     private int tipCount = 0;
  23.     //提示栏高度
  24.     private float tipHeight;
  25.     private Queue<GameObject> visualTipQueue = new Queue<GameObject>();
  26.     //是否可继续生成提示栏,防止频繁点击造成异常
  27.     private bool isOk = true;
  28.     private float timer = 0f;
  29.     private bool startTimer = false;
  30.     private float displayTime = 0.65f;//提示停留展示时间
  31.     private ObjectPool<GameObject> tipPool;
  32.    
  33.     void Start()
  34.     {
  35.         var rect = tipObj.GetComponent<RectTransform>();
  36.         tipHeight = rect.rect.height;
  37.         
  38.         InitTipPool();
  39.     }
  40.     private void Update()
  41.     {
  42.         if (startTimer)
  43.         {
  44.             //定时统一清理提示消息
  45.             timer += Time.deltaTime;
  46.             if (timer > displayTime)
  47.             {
  48.                 ClearAllMsg();
  49.                 timer = 0f;
  50.                 startTimer = false;
  51.             }
  52.         }
  53.         if (Input.GetKeyDown(KeyCode.Space))
  54.         {
  55.             ShowTip("货币不足!");
  56.         }
  57.     }
  58.    
  59.     public void ShowTip(string tip)
  60.     {
  61.         if (!isOk)
  62.         {
  63.             return;
  64.         }
  65.         startTimer = false;
  66.         isOk = false;
  67.         var obj = tipPool.Get();
  68.         var rect1 = obj.GetComponent<RectTransform>();
  69.         var group = obj.GetComponent<CanvasGroup>();
  70.         
  71.         var sequence = DOTween.Sequence();
  72.         if (visualTipQueue.Count > 0)
  73.         {
  74.             sequence.AppendCallback(() =>
  75.             {
  76.                 foreach (var item in visualTipQueue)
  77.                 {
  78.                     var rectValue = item.GetComponent<RectTransform>();
  79.                     rectValue.DOAnchorPosY(rectValue.anchoredPosition.y+tipHeight+offset, 0.2f);
  80.                 }
  81.             });
  82.             sequence.AppendInterval(0.2f);
  83.         }
  84.         sequence.AppendCallback(() =>
  85.         {
  86.             group.alpha = 1;
  87.             obj.transform.SetParent(root);
  88.             obj.transform.localScale = new Vector3(0, 0, 1);
  89.             obj.SetActive(true);
  90.             rect1.anchoredPosition = Vector2.zero;
  91.             visualTipQueue.Enqueue(obj);
  92.             
  93.             tipCount++;
  94.             var txt  = obj.transform.Find("txt").GetComponent<Text>();
  95.             txt.text = tip;
  96.             
  97.             if (tipCount > limitCount)
  98.             {
  99.                 var result = visualTipQueue.Dequeue();
  100.                 tipPool.Release(result);
  101.                 tipCount--;
  102.             }
  103.         });
  104.         sequence.Append(obj.transform.DOScale(Vector3.one, 0.1f));
  105.         sequence.AppendInterval(0.1f);
  106.         sequence.OnComplete(() =>
  107.         {
  108.             timer = 0f;
  109.             isOk = true;
  110.             startTimer = true;
  111.         });
  112.     }
  113.    
  114.     //初始化对象池
  115.     void InitTipPool()
  116.     {
  117.         tipPool = new ObjectPool<GameObject>(() =>
  118.         {
  119.             //创建新对象调用
  120.             var obj = Instantiate(tipObj, objectPool);
  121.             obj.SetActive(false);
  122.             return obj;
  123.         },
  124.         (go) =>
  125.         {
  126.             //获取对象调用
  127.             go.SetActive(true);
  128.             ResetLocal(go.transform);
  129.         },
  130.         (go) =>
  131.         {
  132.             // 在对象放回池子时调用
  133.             go.SetActive(false);
  134.             ResetLocal(go.transform);
  135.             go.transform.SetParent(objectPool);
  136.         },
  137.         (go) =>
  138.         {
  139.             Destroy(go);
  140.         });
  141.     }
  142.    
  143.     //重置本地信息
  144.     void ResetLocal(Transform trans)
  145.     {
  146.         trans.localPosition = Vector3.zero;
  147.         trans.localEulerAngles = Vector3.zero;
  148.         trans.localScale = Vector3.one;
  149.     }
  150.    
  151.     //清空消息
  152.     public void ClearAllMsg()
  153.     {
  154.         var childCount = root.childCount;
  155.         for (var i = 0; i < childCount; i++)
  156.         {
  157.             var child = root.GetChild(i);
  158.             var group = child.GetComponent<CanvasGroup>();
  159.             var rectValue = child.GetComponent<RectTransform>();
  160.             var sequence = DOTween.Sequence();
  161.             sequence.AppendInterval(0.1f * i);
  162.             sequence.Append(rectValue.DOAnchorPosY(rectValue.anchoredPosition.y + tipHeight+flyHeight, 0.2f));
  163.             sequence.Append(group.DOFade(0, 0.1f).OnComplete(() =>
  164.             {
  165.                 visualTipQueue.Dequeue();
  166.                 tipPool.Release(child.gameObject);
  167.                 tipCount--;
  168.             }));
  169.         }
  170.     }
  171. }
复制代码
                                                                                      
左右切换按钮组

本组件一般出现在查看好汉界面,点击左右两个按钮切换查看按钮的具体信息。在好汉列表中,第一个好汉的左按钮不显示,末了一个好汉的右按钮不显示。

  1. using UnityEngine;
  2. using UnityEngine.Events;
  3. using UnityEngine.UI;
  4. public class SwitchCheck : MonoBehaviour
  5. {
  6.     public Button btn_Left;
  7.     public Button btn_Right;
  8.     public Text txt_Check;
  9.     private int sumCount;
  10.     private int curIndex;
  11.     private UnityAction<int> callback;//外部逻辑回调
  12.    
  13.     void Start()
  14.     {
  15.         curIndex = 0;
  16.         InitGroup(10, (index) =>
  17.         {
  18.             txt_Check.text = $"{index}/{sumCount}";
  19.         });
  20.         CheckBtnActive();
  21.         BindBtnLogic(btn_Left, () =>
  22.         {
  23.             var nextIndex = curIndex - 1;
  24.             if (nextIndex < 0)
  25.             {
  26.                 return;
  27.             }
  28.             curIndex = nextIndex;
  29.             CheckBtnActive();
  30.         });
  31.         
  32.         BindBtnLogic(btn_Right, () =>
  33.         {
  34.             var nextIndex = curIndex + 1;
  35.             if (nextIndex >= sumCount)
  36.             {
  37.                 return;
  38.             }
  39.             curIndex = nextIndex;
  40.             CheckBtnActive();
  41.         });
  42.     }
  43.    
  44.     public void InitGroup(int _sumCount,UnityAction<int> _callback)
  45.     {
  46.         sumCount = _sumCount;
  47.         callback = _callback;
  48.     }
  49.    
  50.     //按钮显隐逻辑
  51.     private void CheckBtnActive()
  52.     {
  53.         if (sumCount <= 1)
  54.         {
  55.             btn_Left.gameObject.SetActive(false);
  56.             btn_Right.gameObject.SetActive(false);
  57.         }
  58.         else
  59.         {
  60.             btn_Left.gameObject.SetActive(curIndex >= 1);
  61.             btn_Right.gameObject.SetActive(curIndex <= sumCount-2);
  62.         }
  63.         var showIndex = curIndex + 1;
  64.         callback?.Invoke(showIndex);
  65.     }
  66.    
  67.     //绑定按钮点击回调
  68.     private void BindBtnLogic(Button btn, UnityAction action)
  69.     {
  70.         btn.onClick.RemoveAllListeners();
  71.         if (action != null)
  72.         {
  73.             btn.onClick.AddListener(action);
  74.         }
  75.     }
  76. }
复制代码
帮助说明界面


  1. using System.Text;
  2. using UnityEngine;
  3. using UnityEngine.UI;
  4. public class ComDesc : MonoBehaviour
  5. {
  6.     public Text txt_Title;
  7.     public Text txt_Desc;
  8.     public RectTransform content;
  9.     void Update()
  10.     {
  11.         if (Input.GetKeyDown(KeyCode.Space))
  12.         {
  13.             SetDesc("帮助", "好好学习,天天向上");
  14.         }
  15.             
  16.         if (Input.GetKeyDown(KeyCode.A))
  17.         {
  18.             var str = "好好学习,天天向上";
  19.             StringBuilder sb = new StringBuilder();
  20.             for (var i = 1; i < 100; i++)
  21.             {
  22.                 sb.Append(str);
  23.             }
  24.             SetDesc("帮助", sb.ToString());
  25.         }
  26.     }
  27.     /// <summary>
  28.     /// 设置说明描述
  29.     /// </summary>
  30.     /// <param name="title">界面标题</param>
  31.     /// <param name="desc">说明文本</param>
  32.     public void SetDesc(string title,string desc)
  33.     {
  34.         txt_Title.text = title;
  35.         txt_Desc.text = desc;
  36.         LayoutRebuilder.ForceRebuildLayoutImmediate(content);
  37.     }
  38. }
复制代码
跑马灯消息提示


有消息队列缓存,等待队列中所有消息播放完后,提示才消失。
  1. using System.Collections.Generic;
  2. using DG.Tweening;
  3. using UnityEngine;
  4. using TMPro;
  5. using UnityEngine.Events;
  6. using UnityEngine.UI;
  7. public class Marquee : MonoBehaviour
  8. {
  9.     public TMP_Text tmpTxt;
  10.     public RectTransform maskNode;
  11.     public CanvasGroup canvasGroup;
  12.     private float maskWidth;
  13.     private float unitTime = 0.2f;//计算动画时间自定义标准
  14.     private Queue<MsgNode> marqueeMsg = new Queue<MsgNode>();
  15.     private List<int> idList = new List<int>();
  16.     private bool isPlay;//是否正在播放消息
  17.    
  18.     private class MsgNode
  19.     {
  20.         public int id;
  21.         public string msg;
  22.         public int loopCount;
  23.     }
  24.    
  25.     void Start()
  26.     {
  27.         maskWidth = maskNode.rect.width;
  28.     }
  29.     // Update is called once per frame
  30.     void Update()
  31.     {
  32.         if (Input.GetKeyDown(KeyCode.Space))
  33.         {
  34.             var id = Random.Range(1,100);
  35.             var str = $"id:{id}好好学习,天天向上>>";
  36.             AddMarqueeMsg(id,str,1);
  37.         }
  38.         
  39.         if(marqueeMsg.Count > 0) {
  40.             if (!isPlay)
  41.             {
  42.                 isPlay = true;
  43.                 tmpTxt.rectTransform.anchoredPosition = Vector2.zero;
  44.                 var data = marqueeMsg.Peek();
  45.                 idList.Remove(data.id);
  46.                 DisplayMarqueeMsg(data.msg,data.loopCount, () =>
  47.                 {
  48.                     marqueeMsg.Dequeue();
  49.                     if (marqueeMsg.Count == 0)
  50.                     {
  51.                         canvasGroup.alpha = 0;
  52.                     }
  53.                     isPlay = false;
  54.                 });
  55.             }
  56.         }
  57.     }
  58.     /// <summary>
  59.     /// 在跑马灯消息队列中添加消息
  60.     /// </summary>
  61.     /// <param name="msgId">消息记录的唯一id</param>
  62.     /// <param name="msg">消息内容</param>
  63.     /// <param name="loopCount">循环播放时间</param>
  64.     public void AddMarqueeMsg(int msgId, string msg, int loopCount)
  65.     {
  66.         if (idList.Contains(msgId))
  67.         {
  68.             Debug.LogError("消息已在预播队列");
  69.             return;
  70.         }
  71.         
  72.         if (canvasGroup.alpha < 0.95f)
  73.         {
  74.             canvasGroup.alpha = 1;
  75.         }
  76.         
  77.         idList.Add(msgId);
  78.         marqueeMsg.Enqueue(new MsgNode
  79.         {
  80.             id = msgId,
  81.             msg = msg,
  82.             loopCount = loopCount
  83.         });
  84.     }
  85.    
  86.     /// <summary>
  87.     /// 跑马灯消息播放
  88.     /// </summary>
  89.     /// <param name="msgId">消息记录的唯一id</param>
  90.     /// <param name="msg">消息内容</param>
  91.     /// <param name="loopCount">循环播放时间</param>
  92.     public void DisplayMarqueeMsg(string msg,int loopCount,UnityAction callback)
  93.     {
  94.         tmpTxt.text = msg;
  95.         LayoutRebuilder.ForceRebuildLayoutImmediate(tmpTxt.rectTransform);
  96.         var width = tmpTxt.rectTransform.rect.width+maskWidth;
  97.         var duration = GetDuration(width);
  98.         tmpTxt.rectTransform.DOAnchorPosX(-width, duration)
  99.             .SetEase(Ease.Linear)
  100.             .SetLoops(loopCount, LoopType.Restart)
  101.             .OnComplete(() =>
  102.             {
  103.                 callback?.Invoke();
  104.             });
  105.     }
  106.     //根据消息长度计算动画匀速运行时间
  107.     private float GetDuration(float width)
  108.     {
  109.         var offset1 = (int)width / 100;
  110.         var offset2 = width % 100 == 0 ?0:1;
  111.         var offset = offset1 + offset2;
  112.         return offset * unitTime;
  113.     }
  114. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

怀念夏天

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表