HomeViewTopBar.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using DG.Tweening;
  5. using TMPro;
  6. using UnityEngine;
  7. using UnityEngine.UI;
  8. namespace AppUI.View.Home.Main
  9. {
  10. [Serializable]
  11. public class TopBarButtonInfoTMP
  12. {
  13. public string Name;
  14. public Image Icon;
  15. [Tooltip("选中态图标,不填则保持当前 Sprite 仅切换颜色")]
  16. public Sprite selectedIconSprite;
  17. [Tooltip("未选中态图标,不填则保持当前 Sprite 仅切换颜色")]
  18. public Sprite unselectedIconSprite;
  19. public TMP_Text text;
  20. public bool selected;
  21. public DeviceMode deviceMode;
  22. public GameObject container;
  23. [Tooltip("背景滑动对齐目标(如 Archery / Gun 按钮节点),不填则使用 container")]
  24. public RectTransform tabRect;
  25. }
  26. public class HomeViewTopBar : MonoBehaviour
  27. {
  28. public List<TopBarButtonInfoTMP> topBarButtonInfos;
  29. public UnityEngine.Events.UnityEvent<DeviceMode> onChangeTypeEvent;
  30. [Header("背景滑动")]
  31. [SerializeField] RectTransform btnBg;
  32. [SerializeField] float btnBgMoveDuration = 0.25f;
  33. [SerializeField] Ease btnBgMoveEase = Ease.OutCubic;
  34. [Tooltip("切换时是否同步缩放到 tab 节点尺寸")]
  35. [SerializeField] bool matchTabSize;
  36. [Header("背景 Padding")]
  37. [Tooltip("位置偏移,相对标签本地坐标(X 向右,Y 向上)")]
  38. [SerializeField] Vector2 btnBgPositionOffset;
  39. [Tooltip("在标签尺寸基础上向四周扩展(仅 Match Tab Size 开启时生效)")]
  40. [SerializeField] float btnBgPaddingLeft;
  41. [SerializeField] float btnBgPaddingRight;
  42. [SerializeField] float btnBgPaddingTop;
  43. [SerializeField] float btnBgPaddingBottom;
  44. static readonly Color32 SelectedIconColor = new Color32(0, 0, 0, 255);
  45. static readonly Color32 SelectedTextColor = new Color32(48, 57, 57, 255);
  46. static readonly Color32 UnselectedIconColor = new Color32(255, 255, 255, 255);
  47. static readonly Color32 UnselectedTextColor = new Color32(141, 150, 151, 255);
  48. string _saveKey = "DeviceModeKey";
  49. int _value;
  50. int _valueDefault;
  51. Tween _btnBgTween;
  52. void Start()
  53. {
  54. int deviceValue = GetDeviceModeValue();
  55. if (topBarButtonInfos != null && topBarButtonInfos.Count > 0)
  56. deviceValue = Mathf.Clamp(deviceValue, 0, topBarButtonInfos.Count - 1);
  57. GlobalData.MyDeviceMode = (DeviceMode)deviceValue;
  58. Debug.Log(" GlobalData.MyDeviceMode :" + GlobalData.MyDeviceMode);
  59. onChangeTypeEvent?.Invoke(GlobalData.MyDeviceMode);
  60. UpdateTabVisuals(deviceValue);
  61. StartCoroutine(InitBtnBgPositionAfterLayout(deviceValue));
  62. }
  63. IEnumerator InitBtnBgPositionAfterLayout(int index)
  64. {
  65. yield return null;
  66. Canvas.ForceUpdateCanvases();
  67. MoveBtnBgToTab(index, false);
  68. }
  69. void OnDestroy()
  70. {
  71. _btnBgTween?.Kill();
  72. if (btnBg != null)
  73. btnBg.DOKill();
  74. }
  75. public TopBarButtonInfoTMP GetCurrentTopBarButtonInfo()
  76. {
  77. return topBarButtonInfos[(int)GlobalData.MyDeviceMode];
  78. }
  79. public void onChangeType(int index)
  80. {
  81. if (topBarButtonInfos == null || index < 0 || index >= topBarButtonInfos.Count)
  82. return;
  83. UpdateTabVisuals(index);
  84. MoveBtnBgToTab(index, true);
  85. SetDeviceModeValue(index);
  86. GlobalData.MyDeviceMode = (DeviceMode)index;
  87. Debug.Log("Set GlobalData.MyDeviceMode :" + GlobalData.MyDeviceMode);
  88. onChangeTypeEvent?.Invoke(GlobalData.MyDeviceMode);
  89. }
  90. void UpdateTabVisuals(int selectedIndex)
  91. {
  92. if (topBarButtonInfos == null) return;
  93. for (int i = 0; i < topBarButtonInfos.Count; i++)
  94. {
  95. TopBarButtonInfoTMP topBarButtonInfo = topBarButtonInfos[i];
  96. bool isSelected = i == selectedIndex;
  97. topBarButtonInfo.selected = isSelected;
  98. ApplyIconVisual(topBarButtonInfo, isSelected);
  99. if (topBarButtonInfo.text == null)
  100. continue;
  101. topBarButtonInfo.text.color = isSelected ? SelectedTextColor : UnselectedTextColor;
  102. }
  103. }
  104. static void ApplyIconVisual(TopBarButtonInfoTMP info, bool isSelected)
  105. {
  106. if (info?.Icon == null)
  107. return;
  108. info.Icon.color = isSelected ? SelectedIconColor : UnselectedIconColor;
  109. Sprite targetSprite = isSelected ? info.selectedIconSprite : info.unselectedIconSprite;
  110. if (targetSprite != null)
  111. info.Icon.sprite = targetSprite;
  112. }
  113. void MoveBtnBgToTab(int index, bool animate)
  114. {
  115. if (btnBg == null || topBarButtonInfos == null || index < 0 || index >= topBarButtonInfos.Count)
  116. return;
  117. RectTransform target = GetTabBgTarget(topBarButtonInfos[index]);
  118. if (target == null)
  119. return;
  120. Canvas.ForceUpdateCanvases();
  121. CalcBtnBgTarget(target, out Vector3 targetPos, out Vector2 targetSize);
  122. _btnBgTween?.Kill();
  123. btnBg.DOKill();
  124. if (animate)
  125. {
  126. Sequence seq = DOTween.Sequence();
  127. seq.Join(btnBg.DOMove(targetPos, btnBgMoveDuration).SetEase(btnBgMoveEase));
  128. if (matchTabSize)
  129. seq.Join(btnBg.DOSizeDelta(targetSize, btnBgMoveDuration).SetEase(btnBgMoveEase));
  130. _btnBgTween = seq;
  131. }
  132. else
  133. {
  134. btnBg.position = targetPos;
  135. if (matchTabSize)
  136. btnBg.sizeDelta = targetSize;
  137. }
  138. }
  139. void CalcBtnBgTarget(RectTransform target, out Vector3 worldPos, out Vector2 size)
  140. {
  141. Vector2 localCenter = target.rect.center;
  142. localCenter.x += btnBgPositionOffset.x + (btnBgPaddingRight - btnBgPaddingLeft) * 0.5f;
  143. localCenter.y += btnBgPositionOffset.y + (btnBgPaddingTop - btnBgPaddingBottom) * 0.5f;
  144. Vector3 targetWorldCenter = target.TransformPoint(localCenter);
  145. worldPos = new Vector3(targetWorldCenter.x, targetWorldCenter.y, btnBg.position.z);
  146. size = new Vector2(
  147. target.rect.width + btnBgPaddingLeft + btnBgPaddingRight,
  148. target.rect.height + btnBgPaddingTop + btnBgPaddingBottom);
  149. }
  150. RectTransform GetTabBgTarget(TopBarButtonInfoTMP info)
  151. {
  152. if (info == null)
  153. return null;
  154. if (info.tabRect != null)
  155. return info.tabRect;
  156. if (info.container != null)
  157. return info.container.GetComponent<RectTransform>();
  158. return null;
  159. }
  160. public int GetDeviceModeValue()
  161. {
  162. _value = PlayerPrefs.GetInt(_saveKey, _valueDefault);
  163. return _value;
  164. }
  165. public void SetDeviceModeValue(int value)
  166. {
  167. _value = value;
  168. PlayerPrefs.SetInt(_saveKey, _value);
  169. PlayerPrefs.Save();
  170. }
  171. }
  172. }