yyl
2025-06-04 a7f4c5ecc5268c49f6a6caf769b3ebee6f237662
Main/System/UIBase/UIBase.cs
File was renamed from Main/UI/UIBase.cs
@@ -1,815 +1,815 @@
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,    // 适合做 二级窗口 二级界面
    Top,    // 适合做提示弹窗
    System  // 网络弹窗/其他重要弹窗/系统公告
}
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.None;
    [SerializeField] public UIAnimationType closeAnimationType = UIAnimationType.None;
    [SerializeField][HideInInspector] public float animationDuration = 0.3f;
    [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;
    #endregion
    #region Unity生命周期
    protected virtual void Awake()
    {
        // 确保 DOTween 已初始化
        DOTween.SetTweensCapacity(500, 50);
        // 在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 初始化方法
    // 获取必要的组件
    protected virtual void InitComponent()
    {
        // 获取或添加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>();
        }
        // 获取RectTransform组件
        rectTransform = GetComponent<RectTransform>();
    }
    #endregion
    #region UI操作方法
    // 设置UI层级
    public void SetSortingOrder(int order)
    {
        if (canvas != null)
        {
            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)
                {
                    rectTransform.localScale = Vector3.zero;
                }
                if (canvasGroup != null)
                {
                    canvasGroup.alpha = 0f;
                    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, animationDuration).SetEase(animationEase));
                    }
                    break;
                case UIAnimationType.ScaleInOut:
                    if (rectTransform != null)
                    {
                        currentAnimation.Append(rectTransform.DOScale(originalScale, animationDuration).SetEase(animationEase));
                    }
                    if (canvasGroup != null)
                    {
                        currentAnimation.Join(canvasGroup.DOFade(1f, animationDuration).SetEase(animationEase));
                    }
                    break;
                case UIAnimationType.SlideFromTop:
                case UIAnimationType.SlideFromBottom:
                case UIAnimationType.SlideFromLeft:
                case UIAnimationType.SlideFromRight:
                    if (rectTransform != null)
                    {
                        currentAnimation.Append(rectTransform.DOAnchorPos(originalPosition, animationDuration).SetEase(animationEase));
                    }
                    if (canvasGroup != null)
                    {
                        currentAnimation.Join(canvasGroup.DOFade(1f, animationDuration).SetEase(animationEase));
                    }
                    break;
            }
            // 动画完成后的回调
            currentAnimation.OnComplete(() =>
            {
                isAnimating = false;
                // 启用交互
                if (canvasGroup != null)
                {
                    canvasGroup.interactable = true;
                    canvasGroup.blocksRaycasts = true;
                }
            });
        }
        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, animationDuration).SetEase(animationEase));
                    }
                    break;
                case UIAnimationType.ScaleInOut:
                    if (rectTransform != null)
                    {
                        currentAnimation.Append(rectTransform.DOScale(Vector3.zero, animationDuration).SetEase(animationEase));
                    }
                    if (canvasGroup != null)
                    {
                        currentAnimation.Join(canvasGroup.DOFade(0f, animationDuration).SetEase(animationEase));
                    }
                    break;
                case UIAnimationType.SlideFromTop:
                    if (rectTransform != null)
                    {
                        Vector2 endPos = originalPosition;
                        endPos.y = Screen.height;
                        currentAnimation.Append(rectTransform.DOAnchorPos(endPos, animationDuration).SetEase(animationEase));
                    }
                    if (canvasGroup != null)
                    {
                        currentAnimation.Join(canvasGroup.DOFade(0f, animationDuration).SetEase(animationEase));
                    }
                    break;
                case UIAnimationType.SlideFromBottom:
                    if (rectTransform != null)
                    {
                        Vector2 endPos = originalPosition;
                        endPos.y = -Screen.height;
                        currentAnimation.Append(rectTransform.DOAnchorPos(endPos, animationDuration).SetEase(animationEase));
                    }
                    if (canvasGroup != null)
                    {
                        currentAnimation.Join(canvasGroup.DOFade(0f, animationDuration).SetEase(animationEase));
                    }
                    break;
                case UIAnimationType.SlideFromLeft:
                    if (rectTransform != null)
                    {
                        Vector2 endPos = originalPosition;
                        endPos.x = -Screen.width;
                        currentAnimation.Append(rectTransform.DOAnchorPos(endPos, animationDuration).SetEase(animationEase));
                    }
                    if (canvasGroup != null)
                    {
                        currentAnimation.Join(canvasGroup.DOFade(0f, animationDuration).SetEase(animationEase));
                    }
                    break;
                case UIAnimationType.SlideFromRight:
                    if (rectTransform != null)
                    {
                        Vector2 endPos = originalPosition;
                        endPos.x = Screen.width;
                        currentAnimation.Append(rectTransform.DOAnchorPos(endPos, animationDuration).SetEase(animationEase));
                    }
                    if (canvasGroup != null)
                    {
                        currentAnimation.Join(canvasGroup.DOFade(0f, animationDuration).SetEase(animationEase));
                    }
                    break;
            }
            // 动画完成后的回调 - 修改为调用CompleteClose
            currentAnimation.OnComplete(() =>
            {
                isAnimating = false;
                // 动画完成后,完成关闭过程
                if (isClosing)
                {
                    CompleteClose();
                }
            });
        }
        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
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,    // 适合做 二级窗口 二级界面
    Top,    // 适合做提示弹窗
    System  // 网络弹窗/其他重要弹窗/系统公告
}
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.None;
    [SerializeField] public UIAnimationType closeAnimationType = UIAnimationType.None;
    [SerializeField][HideInInspector] public float animationDuration = 0.3f;
    [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;
    #endregion
    #region Unity生命周期
    protected virtual void Awake()
    {
        // 确保 DOTween 已初始化
        DOTween.SetTweensCapacity(500, 50);
        // 在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 初始化方法
    // 获取必要的组件
    protected virtual void InitComponent()
    {
        // 获取或添加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>();
        }
        // 获取RectTransform组件
        rectTransform = GetComponent<RectTransform>();
    }
    #endregion
    #region UI操作方法
    // 设置UI层级
    public void SetSortingOrder(int order)
    {
        if (canvas != null)
        {
            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)
                {
                    rectTransform.localScale = Vector3.zero;
                }
                if (canvasGroup != null)
                {
                    canvasGroup.alpha = 0f;
                    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, animationDuration).SetEase(animationEase));
                    }
                    break;
                case UIAnimationType.ScaleInOut:
                    if (rectTransform != null)
                    {
                        currentAnimation.Append(rectTransform.DOScale(originalScale, animationDuration).SetEase(animationEase));
                    }
                    if (canvasGroup != null)
                    {
                        currentAnimation.Join(canvasGroup.DOFade(1f, animationDuration).SetEase(animationEase));
                    }
                    break;
                case UIAnimationType.SlideFromTop:
                case UIAnimationType.SlideFromBottom:
                case UIAnimationType.SlideFromLeft:
                case UIAnimationType.SlideFromRight:
                    if (rectTransform != null)
                    {
                        currentAnimation.Append(rectTransform.DOAnchorPos(originalPosition, animationDuration).SetEase(animationEase));
                    }
                    if (canvasGroup != null)
                    {
                        currentAnimation.Join(canvasGroup.DOFade(1f, animationDuration).SetEase(animationEase));
                    }
                    break;
            }
            // 动画完成后的回调
            currentAnimation.OnComplete(() =>
            {
                isAnimating = false;
                // 启用交互
                if (canvasGroup != null)
                {
                    canvasGroup.interactable = true;
                    canvasGroup.blocksRaycasts = true;
                }
            });
        }
        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, animationDuration).SetEase(animationEase));
                    }
                    break;
                case UIAnimationType.ScaleInOut:
                    if (rectTransform != null)
                    {
                        currentAnimation.Append(rectTransform.DOScale(Vector3.zero, animationDuration).SetEase(animationEase));
                    }
                    if (canvasGroup != null)
                    {
                        currentAnimation.Join(canvasGroup.DOFade(0f, animationDuration).SetEase(animationEase));
                    }
                    break;
                case UIAnimationType.SlideFromTop:
                    if (rectTransform != null)
                    {
                        Vector2 endPos = originalPosition;
                        endPos.y = Screen.height;
                        currentAnimation.Append(rectTransform.DOAnchorPos(endPos, animationDuration).SetEase(animationEase));
                    }
                    if (canvasGroup != null)
                    {
                        currentAnimation.Join(canvasGroup.DOFade(0f, animationDuration).SetEase(animationEase));
                    }
                    break;
                case UIAnimationType.SlideFromBottom:
                    if (rectTransform != null)
                    {
                        Vector2 endPos = originalPosition;
                        endPos.y = -Screen.height;
                        currentAnimation.Append(rectTransform.DOAnchorPos(endPos, animationDuration).SetEase(animationEase));
                    }
                    if (canvasGroup != null)
                    {
                        currentAnimation.Join(canvasGroup.DOFade(0f, animationDuration).SetEase(animationEase));
                    }
                    break;
                case UIAnimationType.SlideFromLeft:
                    if (rectTransform != null)
                    {
                        Vector2 endPos = originalPosition;
                        endPos.x = -Screen.width;
                        currentAnimation.Append(rectTransform.DOAnchorPos(endPos, animationDuration).SetEase(animationEase));
                    }
                    if (canvasGroup != null)
                    {
                        currentAnimation.Join(canvasGroup.DOFade(0f, animationDuration).SetEase(animationEase));
                    }
                    break;
                case UIAnimationType.SlideFromRight:
                    if (rectTransform != null)
                    {
                        Vector2 endPos = originalPosition;
                        endPos.x = Screen.width;
                        currentAnimation.Append(rectTransform.DOAnchorPos(endPos, animationDuration).SetEase(animationEase));
                    }
                    if (canvasGroup != null)
                    {
                        currentAnimation.Join(canvasGroup.DOFade(0f, animationDuration).SetEase(animationEase));
                    }
                    break;
            }
            // 动画完成后的回调 - 修改为调用CompleteClose
            currentAnimation.OnComplete(() =>
            {
                isAnimating = false;
                // 动画完成后,完成关闭过程
                if (isClosing)
                {
                    CompleteClose();
                }
            });
        }
        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
}