// 文件位置: Assets/Scripts/TH1_UI/View/Base/View.cs using System; using System.Collections.Generic; using Animancer; using TH1Resource; using UnityEngine; using UnityEngine.UI; namespace TH1_UI.View.Base { public class View : MonoBehaviour { public Canvas ViewCanvas { get { return _canvas; } } public void Initialize(UIWindowProperty windowProperty) { //step #1 设置_winProperty 存储参数,和_canvas 存储canvas对象(提前存引用,避免之后反复getcomponent _winProperty = windowProperty; //_canvas = transform.GetComponent(); 暂时删掉了, 用不着 只有depth会用 //step #2 初始化 PreInitStart(); OnInit(); //step #3 如果需要重新调整size if(_reSize) { _Resize(); } } //目前先架空了 protected virtual void PreInitStart() { } protected virtual void OnInit() { // ✅ [修复] 必须在这里初始化 AnimancerComponent _animancer = GetComponent(); // 如果 Inspector 中没有手动指定打开动画,则使用默认的淡入动画 if (_showAnimationClip == null) { _showAnimationClip = ResourceCache.Instance.AnimCache.UICommonPanelFadeIn; } // 如果 Inspector 中没有手动指定关闭动画,则使用默认的淡出动画 if (_hideAnimationClip == null) { _hideAnimationClip = ResourceCache.Instance.AnimCache.UICommonPanelFadeOut; } // 保留旧系统组件 //_viewAnimation = gameObject.GetComponent(); //_viewAnimationManager = gameObject.GetComponent(); _canvasGroup = gameObject.GetComponent(); if(!(this is ViewSub)) { //ViDebuger.AssertError(_canvasGroup != null, "UI预制根节点必须有CanvasGroup"); } } void _Resize() { // ... (此部分代码未做修改,保持原样) RectTransform rect = transform.Find("Content").GetComponent(); CanvasScaler canvasScaler = GetComponent(); RectTransform canvasRect = GetComponent(); if (canvasScaler.matchWidthOrHeight == 0) { if (canvasRect.rect.height <= 1600) { canvasScaler.matchWidthOrHeight = 1; } } else if (canvasScaler.matchWidthOrHeight - 1 < 0.01f) { if (canvasRect.rect.width <= 720) { canvasScaler.matchWidthOrHeight = 0; } } float canvasRectHeight = canvasRect.rect.height; float factRatio = canvasRectHeight / Screen.height; float safeAreaY = Screen.safeArea.y * factRatio; float safeAreaHeight = Screen.safeArea.height * factRatio; var offset = canvasRectHeight - safeAreaHeight; if (safeAreaY == 0) { if (offset > 0) { rect.offsetMax = new Vector2(rect.offsetMax.x, rect.offsetMax.y - offset); } } else { if ((int)offset == (int)safeAreaY) { rect.offsetMin = new Vector2(rect.offsetMin.x, rect.offsetMin.y + offset); } else if ((int)offset > (int)safeAreaY) { var bottomOffset = safeAreaY; var topOffset = canvasRectHeight - safeAreaHeight - bottomOffset; rect.offsetMin = new Vector2(rect.offsetMin.x, rect.offsetMin.y + bottomOffset); rect.offsetMax = new Vector2(rect.offsetMax.x, rect.offsetMax.y - topOffset); } } } public void SetSortingOrder(int depth) { //暂时删掉了,没有canvas需要的情况 //_canvas.sortingOrder = depth; } public virtual bool IsShow() { return _show && gameObject.activeInHierarchy && _canvasGroup.alpha > 0; } // 🔄 [修改] 重构 Show 方法,确保交互性和回调正确 public virtual void Show() { _show = true; // 备注: gameObject.SetActive(true) 通常由 ViewController 管理,这里保留以防特定情况需要 if (!gameObject.activeSelf) { gameObject.SetActive(true); } _SetAlphaActive(true); if (_animancer != null && _showAnimationClip != null) { var state = _animancer.Play(_showAnimationClip); if (!_enableClick) { _canvasGroup.interactable = false; // 播放期间禁止交互 } state.Events.OnEnd = () => { OnShowAnimFinished(); state.Events.OnEnd = null; }; } else { // 如果没有动画,直接调用完成方法 OnShowAnimFinished(); } } // 🔄 [修改] 重构 Hide 方法,修复语法错误和逻辑漏洞 public virtual void Hide(Action onHideCompleted = null) { // step #1 关闭过程中,一律禁止交互 _show = false; _canvasGroup.interactable = false; // step #2 设置结束时的回调动画包(包含了传入的onHideCompleted) Action onAnimEnd = () => { _OnHideAnimFinished(); onHideCompleted?.Invoke(); }; //step #3 如果animancer正常工作,播放动画,并设定动画结束OnEnd时要执行的回调,并且要清除OnEnd的状态,避免anim没有正常结束反复触发 if (_animancer != null && _hideAnimationClip != null) { var state = _animancer.Play(_hideAnimationClip); state.Events.OnEnd = () => { onAnimEnd(); state.Events.OnEnd = null; }; } //step #4 如果anmancer不正常工作,直接执行动画结束时的回调动画包 else { onAnimEnd(); } } void _SetAlphaActive(bool value) { if (_canvasGroup == null) return; _canvasGroup.alpha = value ? 1.0f : 0; _canvasGroup.interactable = value; _canvasGroup.blocksRaycasts = value; } // ✅ [新增] 一个无参数版本以适配 Animancer protected virtual void OnShowAnimFinished() { if (_canvasGroup != null) { _canvasGroup.interactable = true; // 动画播完,恢复交互 } // 保留旧的注释代码 //UIUtil.SetViewTouchable(true); } // 🔄 [修改] 旧版本,让他调用新版本,以保持向后兼容性 protected virtual void OnShowAnimFinished(ViTimeNodeInterface node) { OnShowAnimFinished(); } void _OnHideAnimFinished() { _SetAlphaActive(false); gameObject.SetActive(false); // 保留旧的注释代码 //UIUtil.SetViewTouchable(true); } // 🔄 [修改] 旧版本,让他调用新版本,以保持向后兼容性 void _OnHideAnimFinished(ViTimeNodeInterface node) { _OnHideAnimFinished(); } public void SetEnableClick(bool value) { _enableClick = value; } //暂时架空了 protected virtual void OnDispose() { //_viewAnimationManager?.Dispose(); //UIUtil.SetViewTouchable(true); } private void OnDestroy() { OnDispose(); } //动画部分 private AnimancerComponent _animancer; [Header("Animancer Animation")] [Tooltip("使用 Animancer 播放的打开动画")] [SerializeField] protected AnimationClip _showAnimationClip; [Tooltip("使用 Animancer 播放的关闭动画")] [SerializeField] protected AnimationClip _hideAnimationClip; //其他部分 protected bool _show; protected Canvas _canvas; protected UIWindowProperty _winProperty; //protected string _showAnimName = string.Empty; //protected string _hideAnimName = string.Empty; //protected Animation _viewAnimation; //protected AnimationManager _viewAnimationManager; protected bool _reSize = false; protected CanvasGroup _canvasGroup; bool _enableClick = false; } }