using System.Collections; 
 | 
using System.Collections.Generic; 
 | 
using UnityEngine; 
 | 
using DG.Tweening; 
 | 
using UnityEngine.UI; // DOTween 插件引用 
 | 
using Cysharp.Threading.Tasks; 
 | 
using System; 
 | 
  
 | 
public enum UILayer 
 | 
{ 
 | 
    Static, // 静态UI 适合做 战斗 主界面 
 | 
    Bottom, // 部分界面特殊处理层级用 
 | 
    Mid,    // 大部分功能窗口都放这层,便于跳转上下层管理(一个界面可以同时存在多个) 
 | 
    System,  // 网络弹窗,信息提示等,其他重要弹窗 
 | 
    Loading,    // 加载界面 
 | 
  
 | 
} 
 | 
  
 | 
public enum UIAnimationType 
 | 
{ 
 | 
    None,       // 无动画 
 | 
    FadeInOut,  // 淡入淡出 
 | 
    ScaleInOut, // 缩放 
 | 
    SlideFromTop, // 从顶部滑入 
 | 
    SlideFromBottom, // 从底部滑入 
 | 
    SlideFromLeft, // 从左侧滑入 
 | 
    SlideFromRight, // 从右侧滑入 
 | 
    ScaleOverInOut,// 缩放根据曲线 
 | 
  
 | 
} 
 | 
  
 | 
[RequireComponent(typeof(Canvas))] 
 | 
[RequireComponent(typeof(CanvasGroup))] 
 | 
[RequireComponent(typeof(CanvasScaler))] 
 | 
public class UIBase : MonoBehaviour 
 | 
{ 
 | 
    #region 属性和变量 
 | 
  
 | 
    // UI基本属性 
 | 
    [SerializeField] public UILayer uiLayer = UILayer.Mid; 
 | 
    [SerializeField][HideInInspector] public string uiName; 
 | 
    [SerializeField] public bool isMainUI = false; 
 | 
  
 | 
    // 新增:是否支持父子关系 
 | 
    // 父子关系:UI拥有的上下级链式关系 
 | 
    // 在非特定情况下 都要拥有父子关系 (一般来说功能都要有父子关系 例外的是例如系统弹窗  
 | 
    // 主界面这种不需要 在制作UI伤  目前的需求是 功能全部做在Middle层) 
 | 
    // 拥有父子关系 在关闭父界面的时候 子界面会连同一起关闭 子界面打开时 父界面的“回合数”会刷新 回合数详见持久化相关的注释 
 | 
    //  
 | 
    [SerializeField] public bool supportParentChildRelation = true;  
 | 
  
 | 
    // 持久化相关 
 | 
    [SerializeField] public bool isPersistent = false; 
 | 
    [SerializeField][HideInInspector] public int maxIdleRounds = 20; 
 | 
  
 | 
  
 | 
    // 动画相关 
 | 
    [SerializeField] public UIAnimationType openAnimationType = UIAnimationType.None; 
 | 
    [SerializeField] public UIAnimationType closeAnimationType = UIAnimationType.None; 
 | 
     
 | 
    [SerializeField]/*[HideInInspector]*/ public float animeDuration = 0.2f; 
 | 
    [SerializeField]public TweenCurve scaleOverInOutCurve; 
 | 
    [SerializeField][HideInInspector] public Ease animationEase = Ease.OutQuad; // 确保使用 DG.Tweening.Ease 
 | 
  
 | 
    // 运行时状态 
 | 
    [HideInInspector] public int lastUsedRound = 0; 
 | 
    [HideInInspector] public UIBase parentUI; 
 | 
  
 | 
    // 子UI管理 
 | 
    [HideInInspector] public List<UIBase> childrenUI = new List<UIBase>(); 
 | 
  
 | 
    [Header("所有UI排版应该在此节点内层")] 
 | 
    [SerializeField] protected RectTransform _rectTransform; //界面默认添加根节点用于表现界面开启关闭动画,或者设置适配用 
 | 
  
 | 
    //遮罩组件在界面开发中生成,遮罩开关和点击空白为其中的组件特性 
 | 
    //  打开遮罩 
 | 
    [Header("遮罩(透明)开关")] 
 | 
    [SerializeField] public bool openMask = false; 
 | 
  
 | 
    //  默认点击空白区域关闭界面 
 | 
    [Header("点击空白关闭")] 
 | 
    [SerializeField] public bool clickEmptySpaceClose = false; 
 | 
  
 | 
    public GameObject screenMask = null; 
 | 
  
 | 
    private Button btnClickEmptyClose; 
 | 
    public Action btnClickEmptyCloseEvent = null;   //提供点击空白区域关闭界面的回调 
 | 
  
 | 
    //  跟OneLevelWin联动 实际上是需要继承自OneLevelWin才能生效的值 使用需要注意 
 | 
    int m_FunctionOrder = 0; 
 | 
    public int functionOrder 
 | 
    { 
 | 
        get { return m_FunctionOrder; } 
 | 
        set { m_FunctionOrder = value; } 
 | 
    } 
 | 
  
 | 
    // 内部状态 
 | 
    protected bool isActive = false; 
 | 
    protected bool isAnimating = false; 
 | 
    protected bool isClosing = false; // 新增:标记是否正在关闭 
 | 
  
 | 
    // 组件引用 
 | 
    protected Canvas canvas; 
 | 
    protected CanvasGroup canvasGroup; 
 | 
  
 | 
    // 动画相关 
 | 
    protected Vector3 originalPosition; 
 | 
    protected Sequence currentAnimation; 
 | 
  
 | 
    public CanvasScaler canvasScaler 
 | 
    { 
 | 
        get; 
 | 
        private set; 
 | 
    } 
 | 
  
 | 
    public const int SafeHeightUp = 50; 
 | 
    public const int SafeHeightDown = 30; 
 | 
    #endregion 
 | 
  
 | 
    #region Unity生命周期 
 | 
  
 | 
    protected virtual void Awake() 
 | 
    { 
 | 
        try 
 | 
        { 
 | 
            InitComponentInternal(); 
 | 
        } 
 | 
        catch (Exception e) 
 | 
        { 
 | 
            Debug.LogError($"{uiName}界面的InitComponentInternal报错: {e.StackTrace}"); 
 | 
        } 
 | 
  
 | 
        try 
 | 
        { 
 | 
            InitComponent(); 
 | 
        } 
 | 
        catch (Exception e) 
 | 
        { 
 | 
            Debug.LogError($"{uiName}界面的InitComponent报错: {e.StackTrace}"); 
 | 
        } 
 | 
  
 | 
        // 保存原始值用于动画 
 | 
        if (_rectTransform != null) 
 | 
        { 
 | 
            if (Screen.height / Screen.width > 1.8)//宽屏需要适配 
 | 
            { 
 | 
                //上下各间隔SafeWidth 
 | 
                _rectTransform.offsetMax = new Vector2(0, -SafeHeightUp);  //上 
 | 
                _rectTransform.offsetMin = new Vector2(0, SafeHeightDown);   //下 
 | 
            } 
 | 
            originalPosition = _rectTransform.anchoredPosition; 
 | 
        } 
 | 
  
 | 
        if (screenMask != null) 
 | 
            screenMask.transform.SetAsFirstSibling(); 
 | 
        InitClickEmptySpaceBtn(); 
 | 
  
 | 
    } 
 | 
  
 | 
    protected virtual void Start() 
 | 
    { 
 | 
        // 子类可以重写此方法进行额外初始化 
 | 
    } 
 | 
  
 | 
    protected async UniTask ApplyClickEmptySpaceClose() 
 | 
    { 
 | 
        if (clickEmptySpaceClose) 
 | 
        { 
 | 
            //延迟x帧后可点击,防止点击过快立即关闭了 
 | 
            await UniTask.Delay(200); 
 | 
            btnClickEmptyClose.enabled = true; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    private void InitClickEmptySpaceBtn() 
 | 
    { 
 | 
        if (!clickEmptySpaceClose) 
 | 
        { 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        btnClickEmptyClose = screenMask.GetComponent<Button>(); 
 | 
  
 | 
        btnClickEmptyClose.AddListener(() => 
 | 
        { 
 | 
            if (btnClickEmptyCloseEvent != null) 
 | 
            { 
 | 
                btnClickEmptyCloseEvent(); 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                CloseWindow(); 
 | 
            } 
 | 
        }); 
 | 
  
 | 
        btnClickEmptyClose.enabled = false; 
 | 
    } 
 | 
  
 | 
  
 | 
    protected async void ExecuteNextFrame(Action _action) 
 | 
    { 
 | 
        await UniTask.DelayFrame(1); 
 | 
        _action?.Invoke(); 
 | 
    } 
 | 
  
 | 
    protected virtual void OnDestroy() 
 | 
    { 
 | 
        // 确保动画被正确清理 
 | 
        if (currentAnimation != null) 
 | 
        { 
 | 
            currentAnimation.Kill(); 
 | 
            currentAnimation = null; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    #endregion 
 | 
  
 | 
    #region 初始化方法 
 | 
  
 | 
    private void InitComponentInternal() 
 | 
    { 
 | 
        // 获取或添加Canvas组件 
 | 
        canvas = GetComponent<Canvas>(); 
 | 
        if (canvas == null) 
 | 
        { 
 | 
            canvas = gameObject.AddComponent<Canvas>(); 
 | 
        } 
 | 
  
 | 
        // 设置Canvas属性 
 | 
        canvas.overrideSorting = true; 
 | 
        canvas.worldCamera = CameraManager.uiCamera; 
 | 
  
 | 
        canvas.sortingLayerID = SortingLayer.NameToID("UI"); // 确保使用正确的排序层 
 | 
  
 | 
        // 获取或添加CanvasGroup组件 
 | 
        canvasGroup = GetComponent<CanvasGroup>(); 
 | 
        if (canvasGroup == null) 
 | 
        { 
 | 
            canvasGroup = gameObject.AddComponent<CanvasGroup>(); 
 | 
        } 
 | 
  
 | 
        // 添加GraphicRaycaster组件(如果没有) 
 | 
        if (GetComponent<UnityEngine.UI.GraphicRaycaster>() == null) 
 | 
        { 
 | 
            gameObject.AddComponent<UnityEngine.UI.GraphicRaycaster>(); 
 | 
        } 
 | 
  
 | 
        canvasScaler = GetComponent<CanvasScaler>(); 
 | 
        canvasScaler.referenceResolution = Constants.DESIGN_RESOLUTION; 
 | 
        canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; 
 | 
        canvasScaler.matchWidthOrHeight = 0; 
 | 
    } 
 | 
  
 | 
    // 获取必要的组件 
 | 
    protected virtual void InitComponent() 
 | 
    { 
 | 
    } 
 | 
  
 | 
    #endregion 
 | 
  
 | 
    #region UI操作方法 
 | 
  
 | 
    // 设置UI层级 
 | 
    public void SetSortingOrder(int order) 
 | 
    { 
 | 
        canvas.sortingOrder = order; 
 | 
    } 
 | 
  
 | 
    protected virtual void OnPreOpen() 
 | 
    { 
 | 
        // 子类可以重写此方法进行额外的预打开操作 
 | 
    } 
 | 
  
 | 
    protected virtual void OnPreClose() 
 | 
    { 
 | 
        // 子类可以重写此方法进行额外的预关闭操作 
 | 
    } 
 | 
  
 | 
    // 打开UI 
 | 
    public void HandleOpen() 
 | 
    { 
 | 
        if (_rectTransform == null) 
 | 
        { 
 | 
            Debug.LogError($"界面: {uiName} 需要设置根节点_rectTransform "); 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        if ((clickEmptySpaceClose || openMask) && screenMask == null) 
 | 
        { 
 | 
            Debug.LogError($"界面: {uiName} 缺少遮罩 "); 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        try 
 | 
        { 
 | 
            OnPreOpen(); 
 | 
        } 
 | 
        catch (Exception e) 
 | 
        { 
 | 
            Debug.LogError($"{uiName}界面的OnPreOpen报错: {e.StackTrace}"); 
 | 
        } 
 | 
  
 | 
        StopCurrentAnimation(); 
 | 
  
 | 
        isClosing = false; 
 | 
        gameObject.SetActive(true); 
 | 
        isActive = true; 
 | 
  
 | 
        PlayOpenAnimation(); 
 | 
  
 | 
        // // 如果后续需要统一处理刘海或者小游戏的界面适配问题 
 | 
        // _rectTransform.offsetMin = new Vector2(0, 10);  //下方 
 | 
        // _rectTransform.offsetMax = new Vector2(0, -50); //上方 
 | 
  
 | 
        try 
 | 
        { 
 | 
            OnOpen(); 
 | 
        } 
 | 
        catch (Exception e) 
 | 
        { 
 | 
            Debug.LogError($"{uiName}界面的OnOpen报错: {e.StackTrace}"); 
 | 
        } 
 | 
  
 | 
        ApplyClickEmptySpaceClose(); 
 | 
  
 | 
        ExecuteNextFrame(() => 
 | 
        { 
 | 
            try 
 | 
            { 
 | 
                NextFrameAfterOpen(); 
 | 
            } 
 | 
            catch (Exception e) 
 | 
            { 
 | 
                Debug.LogError($"{uiName}界面的NextFrameAfterOpen报错: {e.StackTrace}"); 
 | 
            } 
 | 
        }); 
 | 
    } 
 | 
  
 | 
    protected virtual void NextFrameAfterOpen() 
 | 
    { 
 | 
  
 | 
    } 
 | 
  
 | 
    // 关闭UI - 修改后的方法 
 | 
    public void HandleClose() 
 | 
    { 
 | 
        // 如果已经在关闭过程中,直接返回 
 | 
        if (isClosing) return; 
 | 
  
 | 
        if (clickEmptySpaceClose) 
 | 
            btnClickEmptyClose.enabled = false; 
 | 
  
 | 
        try 
 | 
        { 
 | 
            OnPreClose(); 
 | 
        } 
 | 
        catch (Exception e) 
 | 
        { 
 | 
            Debug.LogError($"{uiName}界面的OnPreClose报错: {e.StackTrace}"); 
 | 
        } 
 | 
  
 | 
        StopCurrentAnimation(); 
 | 
  
 | 
        isClosing = true; 
 | 
        isActive = false; 
 | 
  
 | 
        if (canvasGroup != null) 
 | 
        { 
 | 
            canvasGroup.blocksRaycasts = false; 
 | 
        } 
 | 
  
 | 
        PlayCloseAnimation(); 
 | 
  
 | 
        try 
 | 
        { 
 | 
            OnClose(); 
 | 
        } 
 | 
        catch (Exception e) 
 | 
        { 
 | 
            Debug.LogError($"{uiName}界面的OnClose报错: {e.StackTrace}"); 
 | 
        } 
 | 
  
 | 
        if (closeAnimationType == UIAnimationType.None) 
 | 
        { 
 | 
            try 
 | 
            { 
 | 
                CompleteClose(); 
 | 
            } 
 | 
            catch (Exception e) 
 | 
            { 
 | 
                Debug.LogError($"{uiName}界面的CompleteClose报错: {e.StackTrace}"); 
 | 
            } 
 | 
        } 
 | 
        // 否则在动画完成后禁用游戏对象(在PlayCloseAnimation中处理) 
 | 
    } 
 | 
  
 | 
    // 完成关闭过程 - 新增方法 
 | 
    protected virtual void CompleteClose() 
 | 
    { 
 | 
        gameObject.SetActive(false); 
 | 
        isClosing = false; 
 | 
    } 
 | 
  
 | 
    public virtual void CloseWindow() 
 | 
    { 
 | 
        UIManager.Instance.CloseWindow(this, false); 
 | 
    } 
 | 
  
 | 
    public async UniTask DelayCloseWindow(int delayTime = 30) 
 | 
    { 
 | 
        await UniTask.Delay(delayTime); 
 | 
        CloseWindow(); 
 | 
    } 
 | 
  
 | 
    // 刷新UI 
 | 
    public virtual void Refresh() 
 | 
    { 
 | 
        // 子类可以重写此方法实现UI刷新逻辑 
 | 
    } 
 | 
  
 | 
    // 销毁UI 
 | 
    public virtual void Destroy() 
 | 
    { 
 | 
        // 停止所有动画 
 | 
        StopCurrentAnimation(); 
 | 
  
 | 
        ClearChildrenUI(); 
 | 
  
 | 
        if (parentUI != null) 
 | 
        { 
 | 
            parentUI.RemoveChildUI(this); 
 | 
        } 
 | 
  
 | 
        Destroy(gameObject); 
 | 
    } 
 | 
  
 | 
    #endregion 
 | 
     
 | 
    #region 特效相关 
 | 
     
 | 
    /// <summary> 
 | 
    /// 播放UI特效 
 | 
    /// </summary> 
 | 
    /// <param name="id">特效资源名称</param> 
 | 
    /// <param name="parent">特效父节点,默认为当前UI</param> 
 | 
    /// <returns>特效游戏对象</returns> 
 | 
    public UIEffectPlayer PlayUIEffect(int id, Transform parent = null) 
 | 
    { 
 | 
        // 使用默认值 
 | 
        if (parent == null) parent = transform; 
 | 
  
 | 
        return UIEffectPlayer.CreateEffect(id, parent, false); 
 | 
    } 
 | 
  
 | 
    public int GetSortingOrder() 
 | 
    { 
 | 
        if (null != canvas) 
 | 
        { 
 | 
            return canvas.sortingOrder; 
 | 
        } 
 | 
  
 | 
        return 0; 
 | 
    } 
 | 
     
 | 
    #endregion 
 | 
  
 | 
    public bool raycastTarget 
 | 
    { 
 | 
        get; 
 | 
        set; 
 | 
    } = true; 
 | 
  
 | 
    public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera) 
 | 
    { 
 | 
        return raycastTarget; 
 | 
    } 
 | 
  
 | 
    #region 动画方法 
 | 
  
 | 
    // 停止当前正在播放的动画 
 | 
    protected void StopCurrentAnimation() 
 | 
    { 
 | 
        if (currentAnimation != null && currentAnimation.IsActive() && !currentAnimation.IsComplete()) 
 | 
        { 
 | 
            currentAnimation.Kill(false); // 不要完成动画,直接停止 
 | 
            currentAnimation = null; 
 | 
        } 
 | 
        isAnimating = false; 
 | 
    } 
 | 
  
 | 
    // 播放打开动画 
 | 
    protected virtual void PlayOpenAnimation() 
 | 
    { 
 | 
        //禁用交互会引起点透问题, 后续解决可以考虑EventSystem 
 | 
        canvasGroup.blocksRaycasts = true; 
 | 
  
 | 
        if (openAnimationType == UIAnimationType.None) 
 | 
        { 
 | 
            // 无动画,直接启用交互 
 | 
            //  初始值设定好 
 | 
            _ResetToBegin(); 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        isAnimating = true; 
 | 
  
 | 
        // 初始化动画前的状态 
 | 
        switch (openAnimationType) 
 | 
        { 
 | 
            case UIAnimationType.FadeInOut: 
 | 
                if (canvasGroup != null) 
 | 
                { 
 | 
                    canvasGroup.alpha = 0f; 
 | 
                    // canvasGroup.blocksRaycasts = false; 
 | 
                } 
 | 
                if (_rectTransform != null) 
 | 
                { 
 | 
                    _rectTransform.localScale = Vector3.one; 
 | 
                } 
 | 
                break; 
 | 
  
 | 
            case UIAnimationType.ScaleInOut: 
 | 
                if (canvasGroup != null) 
 | 
                { 
 | 
                    canvasGroup.alpha = 1f; 
 | 
                    // canvasGroup.blocksRaycasts = false; 
 | 
                } 
 | 
                if (_rectTransform != null) 
 | 
                { 
 | 
                    _rectTransform.localScale = Vector3.one * 0.3f; 
 | 
                } 
 | 
                break; 
 | 
  
 | 
            case UIAnimationType.SlideFromTop: 
 | 
                _ResetToBegin(); 
 | 
                if (_rectTransform != null) 
 | 
                { 
 | 
                    Vector2 startPos = originalPosition; 
 | 
                    startPos.y = originalPosition.y + Screen.height; 
 | 
                    _rectTransform.anchoredPosition = startPos; 
 | 
                } 
 | 
                break; 
 | 
  
 | 
            case UIAnimationType.SlideFromBottom: 
 | 
                _ResetToBegin(); 
 | 
                if (_rectTransform != null) 
 | 
                { 
 | 
                    Vector2 startPos = originalPosition; 
 | 
                    startPos.y = originalPosition.y-Screen.height; 
 | 
                    _rectTransform.anchoredPosition = startPos; 
 | 
                } 
 | 
                break; 
 | 
  
 | 
            case UIAnimationType.SlideFromLeft: 
 | 
                _ResetToBegin(); 
 | 
                if (_rectTransform != null) 
 | 
                { 
 | 
                    Vector2 startPos = originalPosition; 
 | 
                    startPos.x = originalPosition.x-Screen.width; 
 | 
                    _rectTransform.anchoredPosition = startPos; 
 | 
                } 
 | 
                break; 
 | 
  
 | 
            case UIAnimationType.SlideFromRight: 
 | 
                _ResetToBegin(); 
 | 
                if (_rectTransform != null) 
 | 
                { 
 | 
                    Vector2 startPos = originalPosition; 
 | 
                    startPos.x = originalPosition.x+Screen.width; 
 | 
                    _rectTransform.anchoredPosition = startPos; 
 | 
                } 
 | 
                break; 
 | 
            case UIAnimationType.ScaleOverInOut: 
 | 
                if (canvasGroup != null) 
 | 
                { 
 | 
                    canvasGroup.alpha = 1f; 
 | 
                    // 禁用交互会引起点透问题 
 | 
                    // canvasGroup.blocksRaycasts = false; 
 | 
                } 
 | 
                if (_rectTransform != null) 
 | 
                { 
 | 
                    _rectTransform.localScale = Vector3.one * 0.3f; 
 | 
                } 
 | 
                break; 
 | 
        } 
 | 
  
 | 
        try 
 | 
        { 
 | 
            // 创建动画序列 
 | 
            currentAnimation = DOTween.Sequence(); 
 | 
  
 | 
            // 添加动画 
 | 
            switch (openAnimationType) 
 | 
            { 
 | 
                case UIAnimationType.FadeInOut: 
 | 
                    if (canvasGroup != null) 
 | 
                    { 
 | 
                        currentAnimation.Append(canvasGroup.DOFade(1f, animeDuration).SetEase(animationEase)); 
 | 
                    } 
 | 
                    break; 
 | 
  
 | 
                case UIAnimationType.ScaleInOut: 
 | 
                    if (_rectTransform != null) 
 | 
                    { 
 | 
                        currentAnimation.Append(DOVirtual.Float(0.3f, 1f, animeDuration, (value) => {_rectTransform.localScale = Vector3.one * value;}).SetEase(animationEase)); 
 | 
                    } 
 | 
                    break; 
 | 
  
 | 
                case UIAnimationType.SlideFromTop: 
 | 
                case UIAnimationType.SlideFromBottom: 
 | 
                case UIAnimationType.SlideFromLeft: 
 | 
                case UIAnimationType.SlideFromRight: 
 | 
                    if (_rectTransform != null) 
 | 
                    { 
 | 
                        currentAnimation.Append(_rectTransform.DOAnchorPos(originalPosition, animeDuration).SetEase(animationEase)); 
 | 
                    } 
 | 
                    break; 
 | 
                case UIAnimationType.ScaleOverInOut: 
 | 
                    if (_rectTransform != null) 
 | 
                    { 
 | 
                        float startScale = scaleOverInOutCurve.curve.Evaluate(0f); 
 | 
                        _rectTransform.localScale = Vector3.one * startScale; 
 | 
                        currentAnimation.Append( 
 | 
                            DOTween.To( 
 | 
                                () => _rectTransform.localScale.x, 
 | 
                                (value) => _rectTransform.localScale = Vector3.one * value, 
 | 
                                1f,  
 | 
                                animeDuration 
 | 
                            ) 
 | 
                            .SetEase(scaleOverInOutCurve.curve) 
 | 
                            .OnComplete(() => _rectTransform.localScale = Vector3.one) // 确保最终值1正确 
 | 
                        ); 
 | 
                         
 | 
                    } 
 | 
                    break; 
 | 
            } 
 | 
  
 | 
            // 动画完成后的回调 
 | 
            currentAnimation.OnComplete(() => 
 | 
            { 
 | 
                isAnimating = false; 
 | 
                _ResetToBegin(); 
 | 
                OnOpenAnimationComplete(); 
 | 
  
 | 
                // 启用交互 
 | 
                if (canvasGroup != null) 
 | 
                { 
 | 
                    canvasGroup.blocksRaycasts = true; 
 | 
                } 
 | 
  
 | 
            }); 
 | 
  
 | 
            // currentAnimation.ingoreTimeScale = true; 
 | 
  
 | 
            currentAnimation.Play(); 
 | 
        } 
 | 
        catch (System.Exception e) 
 | 
        { 
 | 
            Debug.LogError($"播放打开动画时出错: {e.StackTrace}"); 
 | 
  
 | 
            // 出错时确保UI可见并可交互 
 | 
            if (canvasGroup != null) 
 | 
            { 
 | 
                canvasGroup.alpha = 1f; 
 | 
                canvasGroup.blocksRaycasts = true; 
 | 
            } 
 | 
            isAnimating = false; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    // private void Update() 
 | 
    // { 
 | 
    //     Debug.LogError(_rectTransform.parent.name + ":" + _rectTransform.anchoredPosition); 
 | 
    // } 
 | 
  
 | 
    private void _ResetToBegin() 
 | 
    { 
 | 
        if (canvasGroup != null) 
 | 
        { 
 | 
            canvasGroup.alpha = 1f; 
 | 
            canvasGroup.blocksRaycasts = true; 
 | 
        } 
 | 
        if (_rectTransform != null) 
 | 
        { 
 | 
            _rectTransform.localScale = Vector3.one; 
 | 
        } 
 | 
  
 | 
        if (_rectTransform != null) 
 | 
        { 
 | 
            _rectTransform.anchoredPosition = originalPosition; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    protected virtual void OnOpenAnimationComplete() 
 | 
    { 
 | 
  
 | 
    } 
 | 
  
 | 
    // 播放关闭动画 - 修改后的方法 
 | 
    protected virtual void PlayCloseAnimation() 
 | 
    { 
 | 
        if (closeAnimationType == UIAnimationType.None) 
 | 
        { 
 | 
            // 无动画,直接返回,让HandleClose方法处理 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        isAnimating = true; 
 | 
  
 | 
        try 
 | 
        { 
 | 
            // 创建动画序列 
 | 
            currentAnimation = DOTween.Sequence(); 
 | 
  
 | 
            // 添加动画 
 | 
            switch (closeAnimationType) 
 | 
            { 
 | 
                case UIAnimationType.FadeInOut: 
 | 
                    if (canvasGroup != null) 
 | 
                    { 
 | 
                        currentAnimation.Append(canvasGroup.DOFade(0.1f, animeDuration).SetEase(animationEase)); 
 | 
                    } 
 | 
                    break; 
 | 
  
 | 
                case UIAnimationType.ScaleInOut: 
 | 
                case UIAnimationType.ScaleOverInOut: 
 | 
                    if (_rectTransform != null) 
 | 
                    { 
 | 
                        currentAnimation.Append(DOVirtual.Float(1f, 0.3f, animeDuration, (value) => {_rectTransform.localScale = Vector3.one * value;}).SetEase(animationEase)); 
 | 
                    } 
 | 
                    break; 
 | 
  
 | 
                case UIAnimationType.SlideFromTop: 
 | 
                    if (_rectTransform != null) 
 | 
                    { 
 | 
                        Vector2 endPos = originalPosition; 
 | 
                        endPos.y = Screen.height; 
 | 
                        currentAnimation.Append(_rectTransform.DOAnchorPos(endPos, animeDuration).SetEase(animationEase)); 
 | 
                    } 
 | 
                    break; 
 | 
  
 | 
                case UIAnimationType.SlideFromBottom: 
 | 
                    if (_rectTransform != null) 
 | 
                    { 
 | 
                        Vector2 endPos = originalPosition; 
 | 
                        endPos.y = -Screen.height; 
 | 
                        currentAnimation.Append(_rectTransform.DOAnchorPos(endPos, animeDuration).SetEase(animationEase)); 
 | 
                    } 
 | 
                    break; 
 | 
  
 | 
                case UIAnimationType.SlideFromLeft: 
 | 
                    if (_rectTransform != null) 
 | 
                    { 
 | 
                        Vector2 endPos = originalPosition; 
 | 
                        endPos.x = -Screen.width; 
 | 
                        currentAnimation.Append(_rectTransform.DOAnchorPos(endPos, animeDuration).SetEase(animationEase)); 
 | 
                    } 
 | 
                    break; 
 | 
  
 | 
                case UIAnimationType.SlideFromRight: 
 | 
                    if (_rectTransform != null) 
 | 
                    { 
 | 
                        Vector2 endPos = originalPosition; 
 | 
                        endPos.x = Screen.width; 
 | 
                        currentAnimation.Append(_rectTransform.DOAnchorPos(endPos, animeDuration).SetEase(animationEase)); 
 | 
                    } 
 | 
                    break; 
 | 
            } 
 | 
  
 | 
            // 动画完成后的回调 - 修改为调用CompleteClose 
 | 
            currentAnimation.OnComplete(() => 
 | 
            { 
 | 
                isAnimating = false; 
 | 
                if (isClosing) 
 | 
                { 
 | 
                    try 
 | 
                    { 
 | 
                        CompleteClose(); 
 | 
                    } 
 | 
                    catch (Exception e) 
 | 
                    { 
 | 
                        Debug.LogError($"{uiName}界面的CompleteClose报错: {e.StackTrace}"); 
 | 
                    } 
 | 
                } 
 | 
            }); 
 | 
  
 | 
            currentAnimation.Play(); 
 | 
        } 
 | 
        catch (System.Exception e) 
 | 
        { 
 | 
            Debug.LogError($"播放关闭动画时出错: {e.StackTrace}"); 
 | 
             
 | 
            // 出错时直接完成关闭 
 | 
            isAnimating = false; 
 | 
            CompleteClose(); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    #endregion 
 | 
  
 | 
    #region 子UI管理 
 | 
  
 | 
    // 添加子UI 
 | 
    public void AddChildUI(UIBase childUI) 
 | 
    { 
 | 
        if (childUI != null && !childrenUI.Contains(childUI)) 
 | 
        { 
 | 
            childrenUI.Add(childUI); 
 | 
            childUI.parentUI = this; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    // 移除子UI 
 | 
    public void RemoveChildUI(UIBase childUI) 
 | 
    { 
 | 
        if (childUI != null && childrenUI.Contains(childUI)) 
 | 
        { 
 | 
            childrenUI.Remove(childUI); 
 | 
            childUI.parentUI = null; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    // 清空所有子UI 
 | 
    public void ClearChildrenUI() 
 | 
    { 
 | 
        for (int i = childrenUI.Count - 1; i >= 0; i--) 
 | 
        { 
 | 
            if (childrenUI[i] != null) 
 | 
            { 
 | 
                childrenUI[i].parentUI = null; 
 | 
            } 
 | 
        } 
 | 
  
 | 
        childrenUI.Clear(); 
 | 
    } 
 | 
  
 | 
    public bool IsActive() 
 | 
    { 
 | 
        return isActive; 
 | 
    } 
 | 
  
 | 
    #endregion 
 | 
  
 | 
    #region 回调方法 
 | 
  
 | 
    // UI打开时的回调 
 | 
    protected virtual void OnOpen() 
 | 
    { 
 | 
        // 子类可以重写此方法实现打开UI时的逻辑 
 | 
    } 
 | 
  
 | 
    // UI关闭时的回调 
 | 
    protected virtual void OnClose() 
 | 
    { 
 | 
        // 子类可以重写此方法实现关闭UI时的逻辑 
 | 
    } 
 | 
  
 | 
    #endregion 
 | 
} 
 |