ModuleView.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. using AppUI.Manager.View;
  2. using DG.Tweening;
  3. using TMPro;
  4. using UnityEngine;
  5. using UnityEngine.Events;
  6. using UnityEngine.UI;
  7. namespace AppUI.View.Component
  8. {
  9. /// <summary>
  10. /// 运行时挂在 <c>Resources/Manager/ModuleView</c> 实例上,绑定层级:
  11. /// ModuleView / BG、Frame / GameObject(Image + Text TMP)、BtnAgree;拒绝按钮节点若存在则仅隐藏不参与逻辑。
  12. /// 弹出与关闭参考 <see cref="PopupMgr"/> 的 Tip:Frame 缩放进入,同意后缩放消失再 <see cref="Object.Destroy"/>。
  13. /// </summary>
  14. public class ModuleView : MonoBehaviour
  15. {
  16. const string PathFrame = "Frame";
  17. const string PathContentRow = "Frame/GameObject";
  18. const string PathContentImage = "Frame/GameObject/Image";
  19. const string PathContentTextTmp = "Frame/GameObject/Text (TMP)";
  20. const string PathContentTextLegacy = "Frame/Text";
  21. const string PathBtnReject = "Frame/BtnReject";
  22. const string PathBtnAgree = "Frame/BtnAgree";
  23. const string PathButtonLabelTmp = "Text (TMP)";
  24. const float PopInDuration = 0.25f;
  25. const float PopOutDuration = 0.3f;
  26. public string text;
  27. public string textKey;
  28. public object[] textFormatArgs = { };
  29. /// <summary>左侧图标;为 null 则保持预制体默认且不隐藏。</summary>
  30. public Sprite contentIcon;
  31. public UnityAction onAgree;
  32. public string onAgreeTextKey;
  33. /// <summary>为 true(默认)时,点击同意会先播放收起动画再销毁自身。</summary>
  34. public bool willDestroyAfterClick = true;
  35. bool _dismissing;
  36. Tween _popTween;
  37. public static ModuleView Show()
  38. {
  39. ViewConfig viewConfig = ViewManager.GetConfig(UIPrefabType.ModuleView);
  40. GameObject go = Instantiate(Resources.Load<GameObject>(viewConfig.path));
  41. return go.AddComponent<ModuleView>();
  42. }
  43. void OnDestroy()
  44. {
  45. _popTween?.Kill();
  46. transform.DOKill(true);
  47. }
  48. void Start()
  49. {
  50. HideRejectIfPresent();
  51. BindContentText();
  52. ApplyContentIcon();
  53. BindAgreeButton();
  54. TrySetButtonLabelKey(PathBtnAgree, onAgreeTextKey);
  55. var frameRt = transform.Find(PathFrame) as RectTransform;
  56. if (frameRt != null)
  57. LayoutRebuilder.ForceRebuildLayoutImmediate(frameRt);
  58. PlayPopIn();
  59. }
  60. void HideRejectIfPresent()
  61. {
  62. Transform reject = transform.Find(PathBtnReject);
  63. if (reject != null)
  64. reject.gameObject.SetActive(false);
  65. }
  66. void PlayPopIn()
  67. {
  68. var frame = transform.Find(PathFrame) as RectTransform;
  69. if (frame == null)
  70. return;
  71. frame.DOKill();
  72. frame.localScale = Vector3.zero;
  73. _popTween = frame
  74. .DOScale(1f, PopInDuration)
  75. .SetEase(Ease.OutBack)
  76. .SetUpdate(true);
  77. }
  78. /// <summary>与点击同意后的收起一致:缩放 Frame 后销毁(不再次触发 <see cref="onAgree"/>)。</summary>
  79. public void CloseWithTween()
  80. {
  81. if (_dismissing)
  82. return;
  83. if (!willDestroyAfterClick)
  84. return;
  85. _dismissing = true;
  86. PlayPopOutAndDestroy();
  87. }
  88. void BindAgreeButton()
  89. {
  90. Transform btnTr = transform.Find(PathBtnAgree);
  91. if (btnTr == null)
  92. return;
  93. var button = btnTr.GetComponent<Button>();
  94. if (button == null)
  95. return;
  96. button.onClick.AddListener(OnAgreeClicked);
  97. }
  98. void OnAgreeClicked()
  99. {
  100. if (_dismissing)
  101. return;
  102. onAgree?.Invoke();
  103. if (!willDestroyAfterClick)
  104. return;
  105. _dismissing = true;
  106. PlayPopOutAndDestroy();
  107. }
  108. void PlayPopOutAndDestroy()
  109. {
  110. Transform btnTr = transform.Find(PathBtnAgree);
  111. if (btnTr != null)
  112. {
  113. var button = btnTr.GetComponent<Button>();
  114. if (button != null)
  115. button.interactable = false;
  116. }
  117. var frame = transform.Find(PathFrame) as RectTransform;
  118. if (frame == null)
  119. {
  120. Destroy(gameObject);
  121. return;
  122. }
  123. _popTween?.Kill();
  124. frame.DOKill();
  125. _popTween = frame
  126. .DOScale(0f, PopOutDuration)
  127. .SetEase(Ease.InBack)
  128. .SetUpdate(true)
  129. .OnComplete(() => Destroy(gameObject));
  130. }
  131. void BindContentText()
  132. {
  133. Transform tmpTr = transform.Find(PathContentTextTmp);
  134. if (tmpTr != null)
  135. {
  136. if (!string.IsNullOrEmpty(textKey))
  137. {
  138. var t2 = tmpTr.gameObject.GetComponent<TextAutoLanguage2>();
  139. if (t2 == null)
  140. t2 = tmpTr.gameObject.AddComponent<TextAutoLanguage2>();
  141. t2.textFormatArgs = textFormatArgs;
  142. t2.SetTextKey(textKey);
  143. }
  144. else
  145. {
  146. var tmp = tmpTr.GetComponent<TMP_Text>();
  147. if (tmp != null)
  148. tmp.text = text ?? string.Empty;
  149. }
  150. return;
  151. }
  152. Transform legacyTr = transform.Find(PathContentTextLegacy);
  153. if (legacyTr == null)
  154. return;
  155. if (!string.IsNullOrEmpty(textKey))
  156. {
  157. var t2 = legacyTr.gameObject.GetComponent<TextAutoLanguage2>();
  158. if (t2 == null)
  159. t2 = legacyTr.gameObject.AddComponent<TextAutoLanguage2>();
  160. t2.textFormatArgs = textFormatArgs;
  161. t2.SetTextKey(textKey);
  162. }
  163. else
  164. {
  165. var uguiText = legacyTr.GetComponent<Text>();
  166. if (uguiText != null)
  167. uguiText.text = text ?? string.Empty;
  168. else
  169. {
  170. var tmp = legacyTr.GetComponent<TMP_Text>();
  171. if (tmp != null)
  172. tmp.text = text ?? string.Empty;
  173. }
  174. }
  175. }
  176. void ApplyContentIcon()
  177. {
  178. if (contentIcon == null)
  179. return;
  180. Transform imgTr = transform.Find(PathContentImage);
  181. if (imgTr == null)
  182. return;
  183. var image = imgTr.GetComponent<Image>();
  184. if (image != null)
  185. {
  186. image.sprite = contentIcon;
  187. image.enabled = true;
  188. }
  189. }
  190. static void TrySetButtonLabelKey(Transform buttonRoot, string key)
  191. {
  192. if (buttonRoot == null || string.IsNullOrEmpty(key))
  193. return;
  194. Transform labelTr = buttonRoot.Find(PathButtonLabelTmp);
  195. GameObject labelGo = labelTr != null
  196. ? labelTr.gameObject
  197. : buttonRoot.GetComponentInChildren<TMP_Text>(true)?.gameObject;
  198. if (labelGo == null)
  199. return;
  200. var t2 = labelGo.GetComponent<TextAutoLanguage2>();
  201. if (t2 == null)
  202. t2 = labelGo.AddComponent<TextAutoLanguage2>();
  203. t2.SetTextKey(key);
  204. }
  205. void TrySetButtonLabelKey(string buttonPath, string key)
  206. {
  207. TrySetButtonLabelKey(transform.Find(buttonPath), key);
  208. }
  209. /// <summary>仅隐藏 <c>Frame/GameObject/Image</c>,不改文案。</summary>
  210. public void SetContentImageVisible(bool visible)
  211. {
  212. Transform imgTr = transform.Find(PathContentImage);
  213. if (imgTr == null)
  214. return;
  215. var image = imgTr.GetComponent<Image>();
  216. if (image != null)
  217. image.enabled = visible;
  218. }
  219. /// <summary>控制左侧图文行整行显隐。</summary>
  220. public void SetContentRowVisible(bool visible)
  221. {
  222. Transform row = transform.Find(PathContentRow);
  223. if (row != null)
  224. row.gameObject.SetActive(visible);
  225. }
  226. }
  227. }