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 // 从右侧滑入 
 | 
} 
 | 
  
 | 
[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; 
 | 
    [SerializeField] public bool supportParentChildRelation = true; // 新增:是否支持父子关系 
 | 
  
 | 
    // 持久化相关 
 | 
    [SerializeField] public bool isPersistent = false; 
 | 
    [SerializeField][HideInInspector] public int maxIdleRounds = 20; 
 | 
  
 | 
    // 动画相关 
 | 
    [SerializeField] public UIAnimationType openAnimationType = UIAnimationType.ScaleInOut; 
 | 
    [SerializeField] public UIAnimationType closeAnimationType = UIAnimationType.None; 
 | 
    [SerializeField]/*[HideInInspector]*/ public float animeDuration = 0.2f; 
 | 
    [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>(); 
 | 
  
 | 
    //  打开遮罩 
 | 
    [SerializeField] public bool openMask = false; 
 | 
  
 | 
    //  点击空白区域关闭界面 
 | 
    [SerializeField] public bool clickEmptySpaceClose = false; 
 | 
  
 | 
    private GameObject screenMask = null; 
 | 
  
 | 
    private Button btnClickEmptyClose; 
 | 
  
 | 
    protected int functionOrder = 0; 
 | 
  
 | 
    // 内部状态 
 | 
    protected bool isActive = false; 
 | 
    protected bool isAnimating = false; 
 | 
    protected bool isClosing = false; // 新增:标记是否正在关闭 
 | 
  
 | 
    // 组件引用 
 | 
    protected Canvas canvas; 
 | 
    protected CanvasGroup canvasGroup; 
 | 
    protected RectTransform rectTransform; 
 | 
  
 | 
    // 动画相关 
 | 
    protected Vector3 originalScale; 
 | 
    protected Vector3 originalPosition; 
 | 
    protected Sequence currentAnimation; 
 | 
  
 | 
    private CanvasScaler canvasScaler; 
 | 
  
 | 
    #endregion 
 | 
  
 | 
    #region Unity生命周期 
 | 
  
 | 
    protected virtual void Awake() 
 | 
    { 
 | 
        // 确保 DOTween 已初始化 
 | 
        DOTween.SetTweensCapacity(500, 50); 
 | 
  
 | 
        //  防止有人不写base.InitComponent引发错误 所以拆分 
 | 
        InitComponentInternal(); 
 | 
        // 在Awake中进行基本初始化 
 | 
        InitComponent(); 
 | 
  
 | 
        // 保存原始值用于动画 
 | 
        if (rectTransform != null) 
 | 
        { 
 | 
            originalScale = rectTransform.localScale; 
 | 
            originalPosition = rectTransform.anchoredPosition; 
 | 
        } 
 | 
  
 | 
        ApplySettings(); 
 | 
  
 | 
        if (openMask) 
 | 
        { 
 | 
            screenMask = GameObject.Instantiate(Resources.Load<GameObject>("Prefabs/ScreenMask"), transform); 
 | 
            screenMask.transform.localScale = Vector3.one; 
 | 
            screenMask.transform.localPosition = Vector3.zero; 
 | 
            screenMask.transform.SetAsFirstSibling(); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    protected virtual void Start() 
 | 
    { 
 | 
        // 子类可以重写此方法进行额外初始化 
 | 
    } 
 | 
  
 | 
    protected async UniTask ApplySettings() 
 | 
    { 
 | 
        await UniTask.DelayFrame(5); 
 | 
  
 | 
        if (null != transform) 
 | 
        { 
 | 
            if (clickEmptySpaceClose) 
 | 
            { 
 | 
                GameObject goBtnESC = GameObject.Instantiate(Resources.Load<GameObject>("Prefabs/ClickEmptyCloseMask"), transform); 
 | 
                //  Load 
 | 
                btnClickEmptyClose = goBtnESC.GetComponent<Button>(); 
 | 
                btnClickEmptyClose.AddListener(CloseWindow); 
 | 
                btnClickEmptyClose.transform.SetAsFirstSibling(); 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    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; 
 | 
  
 | 
        // 获取或添加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>(); 
 | 
  
 | 
        // 获取RectTransform组件 
 | 
        rectTransform = GetComponent<RectTransform>(); 
 | 
    } 
 | 
  
 | 
    // 获取必要的组件 
 | 
    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() 
 | 
    { 
 | 
        OnPreOpen(); 
 | 
        // 如果正在播放动画,先停止 
 | 
        StopCurrentAnimation(); 
 | 
  
 | 
        // 重置关闭标记 
 | 
        isClosing = false; 
 | 
         
 | 
        gameObject.SetActive(true); 
 | 
        isActive = true; 
 | 
  
 | 
        // 根据动画类型播放打开动画 
 | 
        PlayOpenAnimation(); 
 | 
  
 | 
        OnOpen(); 
 | 
    } 
 | 
  
 | 
    // 关闭UI - 修改后的方法 
 | 
    public void HandleClose() 
 | 
    { 
 | 
        // 如果已经在关闭过程中,直接返回 
 | 
        if (isClosing) return; 
 | 
         
 | 
        OnPreClose(); 
 | 
         
 | 
        // 如果正在播放动画,先停止 
 | 
        StopCurrentAnimation(); 
 | 
  
 | 
        // 设置关闭标记 
 | 
        isClosing = true; 
 | 
        isActive = false; 
 | 
         
 | 
        // 禁用交互但保持可见 
 | 
        if (canvasGroup != null) 
 | 
        { 
 | 
            canvasGroup.interactable = false; 
 | 
            canvasGroup.blocksRaycasts = false; 
 | 
        } 
 | 
  
 | 
        // 根据动画类型播放关闭动画 
 | 
        PlayCloseAnimation(); 
 | 
  
 | 
        // 调用关闭回调 
 | 
        OnClose(); 
 | 
         
 | 
        // 如果没有关闭动画,直接禁用游戏对象 
 | 
        if (closeAnimationType == UIAnimationType.None) 
 | 
        { 
 | 
            CompleteClose(); 
 | 
        } 
 | 
        // 否则在动画完成后禁用游戏对象(在PlayCloseAnimation中处理) 
 | 
    } 
 | 
  
 | 
    // 完成关闭过程 - 新增方法 
 | 
    protected virtual void CompleteClose() 
 | 
    { 
 | 
        gameObject.SetActive(false); 
 | 
        isClosing = false; 
 | 
    } 
 | 
  
 | 
    public virtual void CloseWindow() 
 | 
    { 
 | 
        UIManager.Instance.CloseWindow(this, false); 
 | 
    } 
 | 
  
 | 
    // 刷新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="effectName">特效资源名称</param> 
 | 
    /// <param name="parent">特效父节点,默认为当前UI</param> 
 | 
    /// <param name="autoDestroy">是否自动销毁,默认为true</param> 
 | 
    /// <param name="destroyDelay">自动销毁延迟时间,默认为5秒</param> 
 | 
    /// <returns>特效游戏对象</returns> 
 | 
    public async UniTask<GameObject> PlayUIEffect(int id, Transform parent = null, bool autoDestroy = true, float destroyDelay = 5f) 
 | 
    { 
 | 
        // 使用默认值 
 | 
        if (parent == null) parent = transform; 
 | 
         
 | 
        EffectConfig effectCfg = EffectConfig.Get(id); 
 | 
  
 | 
        if (null == effectCfg) 
 | 
        { 
 | 
            return null; 
 | 
        } 
 | 
  
 | 
        // 加载特效资源 
 | 
        var effectPrefab = ResManager.Instance.LoadAsset<GameObject>("UIEffect/" + effectCfg.packageName, effectCfg.fxName); 
 | 
        if (effectPrefab == null) 
 | 
        { 
 | 
            Debug.LogError($"加载UI特效失败: {effectCfg.packageName}"); 
 | 
            return null; 
 | 
        } 
 | 
         
 | 
        // 实例化特效 
 | 
        GameObject effectObj = Instantiate(effectPrefab, parent); 
 | 
        effectObj.name = $"Effect_{effectCfg.packageName}"; 
 | 
         
 | 
        // 添加特效穿透阻挡器 
 | 
        EffectPenetrationBlocker blocker = effectObj.AddComponent<EffectPenetrationBlocker>(); 
 | 
        blocker.parentCanvas = canvas; 
 | 
        blocker.UpdateSortingOrder(); 
 | 
         
 | 
        // 自动销毁 
 | 
        if (autoDestroy) 
 | 
        { 
 | 
            Destroy(effectObj, destroyDelay); 
 | 
        } 
 | 
         
 | 
        return effectObj; 
 | 
    } 
 | 
     
 | 
    /// <summary> 
 | 
    /// 在两个UI元素之间播放特效(按照sortingOrder的中间值) 
 | 
    /// </summary> 
 | 
    /// <param name="effectName">特效资源名称</param> 
 | 
    /// <param name="frontElement">前景UI元素(Image或RawImage)</param> 
 | 
    /// <param name="backElement">背景UI元素(Image或RawImage)</param> 
 | 
    /// <param name="autoDestroy">是否自动销毁,默认为true</param> 
 | 
    /// <param name="destroyDelay">自动销毁延迟时间,默认为5秒</param> 
 | 
    /// <returns>特效游戏对象</returns> 
 | 
    public async UniTask<GameObject> PlayEffectBetweenUIElements(string effectName, Graphic frontElement, Graphic backElement, bool autoDestroy = true, float destroyDelay = 5f) 
 | 
    { 
 | 
        if (frontElement == null || backElement == null) 
 | 
        { 
 | 
            Debug.LogError("前景或背景UI元素为空"); 
 | 
            return null; 
 | 
        } 
 | 
         
 | 
        // 确保UI元素在当前UIBase的Canvas下 
 | 
        if (frontElement.canvas != canvas || backElement.canvas != canvas) 
 | 
        { 
 | 
            Debug.LogError("UI元素不在当前UIBase的Canvas下"); 
 | 
            return null; 
 | 
        } 
 | 
         
 | 
        // 加载特效资源 
 | 
        GameObject effectPrefab = ResManager.Instance.LoadAsset<GameObject>("UIEffect", effectName); 
 | 
        if (effectPrefab == null) 
 | 
        { 
 | 
            Debug.LogError($"加载UI特效失败: {effectName}"); 
 | 
            return null; 
 | 
        } 
 | 
         
 | 
        // 创建一个新的GameObject作为特效容器 
 | 
        GameObject container = new GameObject($"EffectContainer_{effectName}"); 
 | 
        container.transform.SetParent(transform, false); 
 | 
         
 | 
        // 设置容器位置 
 | 
        RectTransform containerRect = container.AddComponent<RectTransform>(); 
 | 
        containerRect.anchorMin = new Vector2(0.5f, 0.5f); 
 | 
        containerRect.anchorMax = new Vector2(0.5f, 0.5f); 
 | 
        containerRect.pivot = new Vector2(0.5f, 0.5f); 
 | 
        containerRect.anchoredPosition = Vector2.zero; 
 | 
        containerRect.sizeDelta = new Vector2(100, 100); // 默认大小,可以根据需要调整 
 | 
         
 | 
        // 获取前景和背景元素的siblingIndex 
 | 
        int frontIndex = frontElement.transform.GetSiblingIndex(); 
 | 
        int backIndex = backElement.transform.GetSiblingIndex(); 
 | 
         
 | 
        // 设置特效容器的siblingIndex在两者之间 
 | 
        if (frontIndex > backIndex) 
 | 
        { 
 | 
            // 前景在背景之后,特效应该在中间 
 | 
            container.transform.SetSiblingIndex((frontIndex + backIndex) / 2 + 1); 
 | 
        } 
 | 
        else 
 | 
        { 
 | 
            // 背景在前景之后,特效应该在中间 
 | 
            container.transform.SetSiblingIndex((frontIndex + backIndex) / 2); 
 | 
        } 
 | 
         
 | 
        // 实例化特效 
 | 
        GameObject effectObj = Instantiate(effectPrefab, container.transform); 
 | 
        effectObj.name = $"Effect_{effectName}"; 
 | 
         
 | 
        // 添加特效穿透阻挡器 
 | 
        EffectPenetrationBlocker blocker = effectObj.AddComponent<EffectPenetrationBlocker>(); 
 | 
         
 | 
        // 直接设置特效渲染器的排序顺序 
 | 
        Renderer[] renderers = effectObj.GetComponentsInChildren<Renderer>(true); 
 | 
        foreach (Renderer renderer in renderers) 
 | 
        { 
 | 
            renderer.sortingOrder = canvas.sortingOrder; 
 | 
            renderer.sortingLayerName = canvas.sortingLayerName; 
 | 
        } 
 | 
         
 | 
        // 设置粒子系统渲染器的排序顺序 
 | 
        ParticleSystem[] particleSystems = effectObj.GetComponentsInChildren<ParticleSystem>(true); 
 | 
        foreach (ParticleSystem ps in particleSystems) 
 | 
        { 
 | 
            ParticleSystemRenderer psRenderer = ps.GetComponent<ParticleSystemRenderer>(); 
 | 
            if (psRenderer != null) 
 | 
            { 
 | 
                psRenderer.sortingOrder = canvas.sortingOrder; 
 | 
                psRenderer.sortingLayerName = canvas.sortingLayerName; 
 | 
            } 
 | 
        } 
 | 
         
 | 
        // 自动销毁 
 | 
        if (autoDestroy) 
 | 
        { 
 | 
            Destroy(container, destroyDelay); 
 | 
        } 
 | 
         
 | 
        return effectObj; 
 | 
    } 
 | 
    #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() 
 | 
    { 
 | 
        if (openAnimationType == UIAnimationType.None) 
 | 
        { 
 | 
            // 无动画,直接启用交互 
 | 
            if (canvasGroup != null) 
 | 
            { 
 | 
                canvasGroup.alpha = 1f; 
 | 
                canvasGroup.interactable = true; 
 | 
                canvasGroup.blocksRaycasts = true; 
 | 
            } 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        isAnimating = true; 
 | 
  
 | 
        // 初始化动画前的状态 
 | 
        switch (openAnimationType) 
 | 
        { 
 | 
            case UIAnimationType.FadeInOut: 
 | 
                if (canvasGroup != null) 
 | 
                { 
 | 
                    canvasGroup.alpha = 0f; 
 | 
                    canvasGroup.interactable = false; 
 | 
                    canvasGroup.blocksRaycasts = false; 
 | 
                } 
 | 
                break; 
 | 
  
 | 
            case UIAnimationType.ScaleInOut: 
 | 
                if (rectTransform != null) 
 | 
                { 
 | 
                    canvasScaler.scaleFactor = 0.3f; 
 | 
                    canvasGroup.interactable = false; 
 | 
                    canvasGroup.blocksRaycasts = false; 
 | 
                } 
 | 
                break; 
 | 
  
 | 
            case UIAnimationType.SlideFromTop: 
 | 
                if (rectTransform != null) 
 | 
                { 
 | 
                    Vector2 startPos = originalPosition; 
 | 
                    startPos.y = Screen.height; 
 | 
                    rectTransform.anchoredPosition = startPos; 
 | 
                } 
 | 
                if (canvasGroup != null) 
 | 
                { 
 | 
                    canvasGroup.alpha = 0f; 
 | 
                    canvasGroup.interactable = false; 
 | 
                    canvasGroup.blocksRaycasts = false; 
 | 
                } 
 | 
                break; 
 | 
  
 | 
            case UIAnimationType.SlideFromBottom: 
 | 
                if (rectTransform != null) 
 | 
                { 
 | 
                    Vector2 startPos = originalPosition; 
 | 
                    startPos.y = -Screen.height; 
 | 
                    rectTransform.anchoredPosition = startPos; 
 | 
                } 
 | 
                if (canvasGroup != null) 
 | 
                { 
 | 
                    canvasGroup.alpha = 0f; 
 | 
                    canvasGroup.interactable = false; 
 | 
                    canvasGroup.blocksRaycasts = false; 
 | 
                } 
 | 
                break; 
 | 
  
 | 
            case UIAnimationType.SlideFromLeft: 
 | 
                if (rectTransform != null) 
 | 
                { 
 | 
                    Vector2 startPos = originalPosition; 
 | 
                    startPos.x = -Screen.width; 
 | 
                    rectTransform.anchoredPosition = startPos; 
 | 
                } 
 | 
                if (canvasGroup != null) 
 | 
                { 
 | 
                    canvasGroup.alpha = 0f; 
 | 
                    canvasGroup.interactable = false; 
 | 
                    canvasGroup.blocksRaycasts = false; 
 | 
                } 
 | 
                break; 
 | 
  
 | 
            case UIAnimationType.SlideFromRight: 
 | 
                if (rectTransform != null) 
 | 
                { 
 | 
                    Vector2 startPos = originalPosition; 
 | 
                    startPos.x = Screen.width; 
 | 
                    rectTransform.anchoredPosition = startPos; 
 | 
                } 
 | 
                if (canvasGroup != null) 
 | 
                { 
 | 
                    canvasGroup.alpha = 0f; 
 | 
                    canvasGroup.interactable = false; 
 | 
                    canvasGroup.blocksRaycasts = false; 
 | 
                } 
 | 
                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, originalScale.x, animeDuration, (value) => {canvasScaler.scaleFactor = 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)); 
 | 
                    } 
 | 
                    if (canvasGroup != null) 
 | 
                    { 
 | 
                        currentAnimation.Join(canvasGroup.DOFade(1f, animeDuration).SetEase(animationEase)); 
 | 
                    } 
 | 
                    break; 
 | 
            } 
 | 
  
 | 
            // 动画完成后的回调 
 | 
            currentAnimation.OnComplete(() => 
 | 
            { 
 | 
                isAnimating = false; 
 | 
  
 | 
                // 启用交互 
 | 
                if (canvasGroup != null) 
 | 
                { 
 | 
                    canvasGroup.interactable = true; 
 | 
                    canvasGroup.blocksRaycasts = true; 
 | 
                } 
 | 
            }); 
 | 
  
 | 
            currentAnimation.Play(); 
 | 
        } 
 | 
        catch (System.Exception e) 
 | 
        { 
 | 
            Debug.LogError($"播放打开动画时出错: {e.Message}"); 
 | 
  
 | 
            // 出错时确保UI可见并可交互 
 | 
            if (canvasGroup != null) 
 | 
            { 
 | 
                canvasGroup.alpha = 1f; 
 | 
                canvasGroup.interactable = true; 
 | 
                canvasGroup.blocksRaycasts = true; 
 | 
            } 
 | 
            isAnimating = false; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    // 播放关闭动画 - 修改后的方法 
 | 
    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(0f, animeDuration).SetEase(animationEase)); 
 | 
                    } 
 | 
                    break; 
 | 
  
 | 
                case UIAnimationType.ScaleInOut: 
 | 
                    if (rectTransform != null) 
 | 
                    { 
 | 
                        currentAnimation.Append(DOVirtual.Float(originalScale.x, 0.3f, animeDuration, (value) => {canvasScaler.scaleFactor = 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)); 
 | 
                    } 
 | 
                    if (canvasGroup != null) 
 | 
                    { 
 | 
                        currentAnimation.Join(canvasGroup.DOFade(0f, 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)); 
 | 
                    } 
 | 
                    if (canvasGroup != null) 
 | 
                    { 
 | 
                        currentAnimation.Join(canvasGroup.DOFade(0f, 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)); 
 | 
                    } 
 | 
                    if (canvasGroup != null) 
 | 
                    { 
 | 
                        currentAnimation.Join(canvasGroup.DOFade(0f, 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)); 
 | 
                    } 
 | 
                    if (canvasGroup != null) 
 | 
                    { 
 | 
                        currentAnimation.Join(canvasGroup.DOFade(0f, animeDuration).SetEase(animationEase)); 
 | 
                    } 
 | 
                    break; 
 | 
            } 
 | 
  
 | 
            // 动画完成后的回调 - 修改为调用CompleteClose 
 | 
            currentAnimation.OnComplete(() => 
 | 
            { 
 | 
                isAnimating = false; 
 | 
                 
 | 
                // 动画完成后,完成关闭过程 
 | 
                if (isClosing) 
 | 
                { 
 | 
                    CompleteClose(); 
 | 
                } 
 | 
            }); 
 | 
  
 | 
            currentAnimation.Play(); 
 | 
        } 
 | 
        catch (System.Exception e) 
 | 
        { 
 | 
            Debug.LogError($"播放关闭动画时出错: {e.Message}"); 
 | 
             
 | 
            // 出错时直接完成关闭 
 | 
            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 
 | 
} 
 |