unity UI管理器

news2025/4/2 23:11:56
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

// UI界面基类
public abstract class UIBase : MonoBehaviour
{
    [Header("UI Settings")]
    public bool keepInStack = true; // 是否保留在界面栈中
    public bool destroyWhenClose = false; // 关闭时是否销毁

    // 界面打开关闭事件
    public UnityEvent onOpen;
    public UnityEvent onClose;

    // 界面初始化
    public virtual void Init() { }

    // 界面打开
    // 在UIBase中添加
    public virtual void Open()
    {
        Debug.Log($"Opening {gameObject.name}");
        gameObject.SetActive(true);
        onOpen?.Invoke();
    }

    public virtual void Close()
    {
        Debug.Log($"Closing {gameObject.name}");
        gameObject.SetActive(false);
        onClose?.Invoke();

        if (destroyWhenClose)
        {
            Debug.Log($"Destroying {gameObject.name}");
            Destroy(gameObject);
        }
    }

    // 返回按钮处理(Android返回键或界面返回按钮)
    public virtual void OnBackPressed()
    {
        UIManager.Instance.CloseUI(this);
    }
}




// UI管理器
public class UIManager : MonoBehaviour
{
    private static UIManager _instance;
    public static UIManager Instance => _instance;

    [Header("UI Settings")]
    public Transform uiRoot; // UI根节点
    public GameObject loadingScreen; // 加载界面

    private Dictionary<string, GameObject> _uiPrefabs = new Dictionary<string, GameObject>();
    private Stack<UIBase> _uiStack = new Stack<UIBase>();
    private Dictionary<string, UIBase> _loadedUIs = new Dictionary<string, UIBase>();

    private void Awake()
    {
        if (_instance != null && _instance != this)
        {
            Destroy(gameObject);
            return;
        }

        _instance = this;
        DontDestroyOnLoad(gameObject);
    }

    // 注册UI预制体
    public void RegisterUI(string uiName, GameObject prefab)
    {
        if (!_uiPrefabs.ContainsKey(uiName))
        {
            _uiPrefabs.Add(uiName, prefab);
        }
    }

    // 同步打开UI
    public UIBase OpenUI(string uiName, object data = null)
    {
        if (loadingScreen != null) loadingScreen.SetActive(true);

        UIBase ui = GetOrCreateUI(uiName);
        if (ui == null)
        {
            Debug.LogError($"UI {uiName} not found!");
            if (loadingScreen != null) loadingScreen.SetActive(false);
            return null;
        }

        // 强制激活新UI
        ui.gameObject.SetActive(true);

        // 处理当前UI
        if (_uiStack.Count > 0)
        {
            var currentUI = _uiStack.Peek();

            // 无论keepInStack如何,都关闭当前UI
            currentUI.Close();

            // 如果新UI不保留栈或当前UI需要销毁
            if (!ui.keepInStack || currentUI.destroyWhenClose)
            {
                _uiStack.Pop();
                if (currentUI.destroyWhenClose)
                {
                    _loadedUIs.Remove(currentUI.gameObject.name);
                }
            }
        }

        // 初始化并打开新UI
        ui.Init();
        ui.Open();

        // 添加到栈(如果需要)
        if (ui.keepInStack)
        {
            _uiStack.Push(ui);
        }

        if (loadingScreen != null) loadingScreen.SetActive(false);

        Debug.Log($"当前栈内UI数量: {_uiStack.Count}");
        return ui;
    }

    // 异步打开UI
    public IEnumerator OpenUIAsync(string uiName, object data = null)
    {
        if (loadingScreen != null) loadingScreen.SetActive(true);

        yield return null; // 等待一帧

        UIBase ui = GetOrCreateUI(uiName);
        if (ui == null)
        {
            Debug.LogError($"UI {uiName} not found!");
            if (loadingScreen != null) loadingScreen.SetActive(false);
            yield break;
        }

        if (_uiStack.Count > 0 && !ui.keepInStack)
        {
            var currentUI = _uiStack.Peek();
            currentUI.Close();
        }

        ui.Init();
        ui.Open();

        if (ui.keepInStack)
        {
            _uiStack.Push(ui);
        }

        if (loadingScreen != null) loadingScreen.SetActive(false);
    }

    // 关闭UI
    public void CloseUI(UIBase ui)
    {
        if (ui == null) return;

        ui.Close();

        if (_uiStack.Count > 0 && _uiStack.Peek() == ui)
        {
            _uiStack.Pop();

            // 打开上一个UI
            if (_uiStack.Count > 0)
            {
                var prevUI = _uiStack.Peek();
                prevUI.Open();
            }
        }
    }

    // 关闭当前UI
    public void CloseCurrentUI()
    {
        if (_uiStack.Count > 0)
        {
            CloseUI(_uiStack.Peek());
        }
    }

    // 获取或创建UI
    private UIBase GetOrCreateUI(string uiName)
    {
        // 检查是否已加载
        if (_loadedUIs.TryGetValue(uiName, out UIBase loadedUI))
        {
            return loadedUI;
        }

        // 检查是否有预制体
        if (!_uiPrefabs.TryGetValue(uiName, out GameObject prefab))
        {
            Debug.LogError($"UI prefab {uiName} not registered!");
            return null;
        }

        // 实例化UI
        GameObject uiObj = Instantiate(prefab, uiRoot);
        UIBase ui = uiObj.GetComponent<UIBase>();
        if (ui == null)
        {
            Debug.LogError($"UI {uiName} has no UIBase component!");
            Destroy(uiObj);
            return null;
        }

        uiObj.name = uiName;
        _loadedUIs.Add(uiName, ui);

        return ui;
    }

    // 清空所有UI
    public void ClearAll()
    {
        while (_uiStack.Count > 0)
        {
            var ui = _uiStack.Pop();
            ui.Close();
            if (ui.destroyWhenClose)
            {
                _loadedUIs.Remove(ui.gameObject.name);
            }
        }
    }

    // 处理返回键
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Escape))
        {
            if (_uiStack.Count > 0)
            {
                _uiStack.Peek().OnBackPressed();
            }
        }
    }
}

然后注册UI

using UnityEngine;

public class GameInitializer : MonoBehaviour
{
    [SerializeField] private GameObject LoginInterface;
    [SerializeField] private GameObject SingerOrMulti;
    [SerializeField] private GameObject ModuleSelect;
    [SerializeField] private GameObject SandTableSelect;
    [SerializeField] private GameObject DataReport;
    [SerializeField] private GameObject SettingInterface;
    private void Start()
    {
        // 注册UI预制体
        UIManager.Instance.RegisterUI("LoginInterface", LoginInterface);
        UIManager.Instance.RegisterUI("SingerOrMulti", SingerOrMulti);
        UIManager.Instance.RegisterUI("ModuleSelect", ModuleSelect);
        UIManager.Instance.RegisterUI("SandTableSelect", SandTableSelect);
        UIManager.Instance.RegisterUI("DataReport", DataReport);
        UIManager.Instance.RegisterUI("SettingInterface", SettingInterface);
        // 打开主菜单
        UIManager.Instance.OpenUI("LoginInterface");
    }
}

调用UI界面 是预制体
在这里插入图片描述
脚本要继承UIbase

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2326833.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STRUCTBERT:将语言结构融入预训练以提升深度语言理解

【摘要】最近&#xff0c;预训练语言模型BERT&#xff08;及其经过稳健优化的版本RoBERTa&#xff09;在自然语言理解&#xff08;NLU&#xff09;领域引起了广泛关注&#xff0c;并在情感分类、自然语言推理、语义文本相似度和问答等各种NLU任务中达到了最先进的准确率。受到E…

16-CSS3新增选择器

知识目标 掌握属性选择器的使用掌握关系选择器的使用掌握结构化伪类选择器的使用掌握伪元素选择器的使用 如何减少文档内class属性和id属性的定义&#xff0c;使文档变得更加简洁&#xff1f; 可以通过属性选择器、关系选择器、结构化伪类选择器、伪元素选择器。 1. 属性选择…

SQL Server:用户权限

目录 创建 & 删除1. 创建用户命令整理创建 admin2 用户创建 admin_super 用户 2. 删除用户命令删除 admin2 用户删除 admin_super 用户 3. 创建时权限的区别admin2 用户权限admin_super 用户权限 查看方法一&#xff1a;使用对象资源管理器&#xff08;图形化界面&#xff…

服务器数据恢复—误格式化NTFS文件系统分区别慌,NTFS数据复活秘籍

NTFS文件系统下格式化在理论上不会对数据造成太大影响&#xff0c;但有可能造成部分文件目录结构丢失的情况。下面介绍一个人为误操作导致服务器磁盘阵列中的NTFS文件系统分区被格式化后的服务器数据恢复案例。 服务器数据恢复过程&#xff1a; 1、将故障服务器连接到一台备份…

【3】数据结构的双向链表章

目录标题 双向链表的定义双向链表的初始化双向链表的创建插入操作删除操作 双向链表总代码与调试 双向链表的定义 结点结构组成&#xff1a;数据域&#xff08;data&#xff09;、指针域&#xff08;pre&#xff09;、指针域&#xff08;next&#xff09;。其中&#xff0c; da…

蓝桥杯杯赛-日期模拟

知识点 处理日期 1. 按天枚举日期&#xff1a;逐天遍历起始日期到结束日期范围内的每个日期。 2. 处理闰年&#xff1a;正确判断闰年条件。闰年定义为&#xff1a;年份 满足以下任意一个条件&#xff1a;(闰年的2月只有29天) 满足下面一个条件就是闰年 1> 是 400 的倍数…

搭建开源笔记平台:outline

折腾的意义 为什么要自己搭建一个笔记平台&#xff1f;没理由&#xff0c;就是突然想试试。有时候突然有个想法&#xff0c;搜了一下正好有合适的方案&#xff0c;就顺手试一下。 其实已经有很多成熟的笔记软件&#xff0c;例如Notion/OneNote&#xff0c;但谁不想要一个数据完…

Unity编辑器功能及拓展(2) —Gizmos编辑器绘制功能

Unity中的Gizmos功能是用于在场景视图中绘制辅助图形或图标的工具&#xff0c;帮助开发者在编辑模式下直观调试和可视化游戏对象的位置、范围、方向等信息。 一.定义概述 Gizomsd 概述 Gizoms是Unity提供的一个API&#xff0c;或者叫做一个工具类&#xff0c;包含一系列静态…

电脑屏幕亮度随心控,在Windows上自由调整屏幕亮度的方法

调整电脑屏幕的亮度对于保护视力和适应不同环境光线条件非常重要。无论是在白天强光下还是夜晚昏暗环境中&#xff0c;合适的屏幕亮度都能让您的眼睛更加舒适。本文中简鹿办公小编将向您介绍几种在 Windows 系统中调整屏幕亮度的方法。 方法一&#xff1a;使用快捷键 大多数笔…

presto行转列

presto的行列转换和spark、hive一样也是通过外链语句实现的&#xff0c;只不过语法和关键子有点不同&#xff0c;如下 with tmp1 as (select 1,2,3 as a1,4,5,6 as a2 ) select * from tmp1 cross join unnest(split(tmp1.a1, ,),split(tmp1.a2, ,) ) as b(a1s,a2s) 结果如下

51c自动驾驶~合集15

我自己的原文哦~ https://blog.51cto.com/whaosoft/11720657 #DRAMA 首个基于Mamba的端到端运动规划器&#xff08;新加坡国立&#xff09; 运动规划是一项具有挑战性的任务&#xff0c;在高度动态和复杂的环境中生成安全可行的轨迹&#xff0c;形成自动驾驶汽车的核心能…

拼多多 anti-token unidbg 分析

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 逆向分析 版本7.3-7.4 都试过加密没什…

【Git】5 个分区的切换方式及示例

目录 1. **工作区&#xff08;Working Directory&#xff09;**2. **缓存区&#xff08;Stage/Index&#xff09;**3. **本地仓库&#xff08;Local Repository&#xff09;**4. **远程仓库&#xff08;Remote Repository&#xff09;**5. **贮藏区&#xff08;Stash&#xff0…

Java高频面试之并发编程-02

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;进程和线程的区别是什么&#xff1f; 1. 资源分配与独立性 进程&#xff1a; 独立性&#xff1a;每个进程拥有独立的内存…

openwebui和keycloak集成,使用keycloak的用户名和密码登录

1&#xff0c;实现效果 使用keycloak定义的用户名和密码&#xff0c;直接登录openwebui 2&#xff0c;实现原理 keycloak中用户信息中包含用户名和密码&#xff0c;以及email。 使用keycloak中的用户名和密码登录之后&#xff0c;会用email创建一个openwebui的账号。之后每次…

【区块链安全 | 第八篇】多签机制及恶意多签

部分参考&#xff1a;慢雾科技 文章目录 为什么需要多签多签机制Tron钱包下的恶意多签Tron 钱包多签权限分类Tron 多签机制的运作方式 恶意多签的过程黑客通过多签机制控制账户黑客剥夺用户权限&#xff0c;完全控制账户 恶意多签成因 在区块链中&#xff0c;多签&#xff08;M…

二月公开赛Web-ssrfme

目录 环境搭建 题目分析 分析代码 解题过程 Redis未授权访问 寻找Flag 环境搭建 进入含有docker-compose.yml的文件内&#xff0c;拉取容器镜像 docker-compose up -d 题目分析 访问容器地址172.25.254.200:8091查看题目 分析代码 url通过GET请求访问界面&#xff0c…

告别枯燥工作,走向自动化

嘿&#xff0c;小伙伴们&#xff01;今天给你们介绍两款超实用的RPA办公自动化软件&#xff0c;用它们&#xff0c;再也不用像机器一样做重复劳动啦&#xff0c;超省时间&#xff01; 工具名称&#xff1a;影刀RPA&#xff08;类似产品&#xff0c;八爪鱼 RPA&#xff0c;操作上…

可信数据空间:构筑安全可控数据流通

前言&#xff1a;可信数据空间是一种数据基础设施&#xff0c;发展可信数据空间是全国及各地数据基础设施建设的重要方面。国内数据空间的探索和实践仍然数据探索阶段。本期分享&#xff1a;可信数据空间构筑安全可控数据流通&#xff0c;包括可信数据空间技术介绍、如何助力数…

Zookeeper特性与节点数据类型

数据结构和监听机制 CP 文件系统形式存储 观察者模式监听节点数据变化、 临时节点客户端超时或发生异常节点就会删除 2888同步数据 3888选举端口 1.什么是Zookeeper ZooKeeper 是一个开源的分布式协调框架&#xff0c;是Apache Hadoop 的一个子项目&#xff0c;主要用来…