UnityVR--UIManager--UI管理1

news2025/1/11 18:38:16

目录

前言

UI节点的结构

需要用到的组件

  1. CanvasGroup

  2. Button等控件的OnClick()监听

  3. EventTrigger

建立UI工具集

  1. 管理UI节点

  2.  UIBase包含了以下的工具

建立分面板的管理工具——以主面板MainUi为例


前言

  UI在项目中的重要性不言而喻,并且UI控件的种类繁多(UGUI简单介绍仅仅列举了常用控件和重要参数),不仅需要有一个统一的工具管理器来控制各个UI节点的初始化、排列、 组件等,还需要有一个UIManager在项目中统一控制。

  本篇主要介绍UI的工具集UITools,由于篇幅有限,UIManager放在下一篇。

  UITools提供了一系列的关于UI节点的操作工具,尤其是对于Button、Slider等交互性较强的UI控件来说,集中管理这些工具会使代码重用性大大提高,减少系统消耗。

  先从场景中的UI节点设置开始:

UI节点的结构

  UI面板的结构大致如下图,不同的面板使用Canvas作为载体,在场景显示中,先加载的节点(上面的节点)先显示,后加载的节点覆盖在最上面:

  比如,点击主界面中的Play按钮,显示其中一个Loading面板,这个面板就要放在主面板节点的下面,显示时覆盖在主面板上。

  *注:在不少项目中,大部分的UI面板都是作为预制体的形式存在于Resource资源文件夹中,而场景中只留下UI根节点(空)、UICamera、Main/Middle/……等存放各部分面板的节点(均为空),以及EventSystem。

需要用到的组件

  在之前的UGUI简单介绍中列举了一些UI控件,这些控件上并不一定默认就有我们需要用到的组件,比如:

  1. CanvasGroup

  

  这个组件可以放在Canvas上,通过对于Alpha值的控制,实现面板渐隐渐显的效果。如果安装了DoTween插件,可以实现一个简单的显示动画效果(效果曲线可以参照:Easing Functions Cheat Sheet) 

       canvasGroup = gameObject.AddComponent<CanvasGroup>(); 
       canvasGroup.interactable = false;  //还没显示完全时不允许交互
       canvasGroup.DOFade(0f, 1f); //安装DoTween插件,控制Alfa值,1s内透明度变成0

       //1.5s内按照OutExpo动画曲线显现,完成后回调
       canvasGroup.DOFade(1f, 1.5f).SetEase(Ease.OutExpo).OnComplete(()=>
       {//完成显示之后的回调
          action?.Invoke();  //执行回调
          canvasGroup.interactable = true;  // 面板可以交互
       });  

  2. Button等控件的OnClick()监听

  Button按钮是交互性最强的按钮,其身上的OnClick(),作为按钮按下的监听,在场景中的使用非常频繁。绑定监听的方法可以按以下方式:

  方法一:直接在OnClick()面板添加脚本节点,并指定回调函数

   方法二:代码中动态设置:

        button = transform.GetComponent<Button>();
        button.onClick.AddListener(()=>
        {
            Debug.Log("没想好要干嘛");
        });

  3. EventTrigger

  Button中提供了按钮被按下的事件,而EventTrigger中提供了种类更加丰富的事件

    public enum EventTriggerType
    {
        PointerEnter, //鼠标进入
        PointerExit,  //鼠标离开
        PointerDown,  //鼠标按下
        PointerUp,    //鼠标抬起
        PointerClick, //鼠标点击(鼠标抬起时已不在原UI上时不会触发,在PointerUp之后调用)
        Drag,         //鼠标拖拽
        Drop,         //拖拽结束时鼠标不在被拖拽UI上并且在另外一个UI上时触发(在PointerUp之后)
        Scroll,       //滑轮滚动时
        UpdateSelected, //被选中后的每一帧
        Select,       //在被选中时
        Deselect,     //结束选中时
        Move,         //按方向键时
        InitializePotentialDrag,  //初始化拖拽(在PointerDown之后,PoinerUp之前调用,点击就会调用)
        BeginDrag,    //拖拽开始(鼠标按下不移动不会触发)
        EndDrag,      //拖拽结束
        Submit,       //默认为Enter键
        Cancel        //默认为Enter键
    }

  添加监听及回调的方式和OnClick()一样,也可以在面板中添加,或者在脚本中动态添加。

  方法一:点击"AddNewEventType"->找到需要绑定的事件,点击“+”号键,并添加回调函数

 

   方法二:代码中添加

        EventTrigger.Entry entry = new EventTrigger.Entry();
        entry.callback = new EventTrigger.TriggerEvent();
        entry.callback.AddListener(callBack);
        entry.eventID = EventTriggerType.PointerClick; //添加PointerClick类型的事件
        transform.GetComponent<EventTrigger>().triggers.Add(entry);

建立UI工具集

   建立一个基类UIBase.cs,管理所有的UI节点,并且设置一些工具控制面板的初始化、显示、隐藏、添加事件等,之后在场景中可以方便地调用。

  1. 管理UI节点

 首先,我们需要获取并管理所有的UI节点。不过从上面的UI结构图中可以看到,UI的层级结构和节点非常多,不能每次使用时都遍历一遍。因此,在管理这些数据之前,先要使用Tag标签把UI控件分类,需要经常交互的控件使用“UIEvent”标签,仅需控制显示的使用“UIGO”标签,其他一些完全不需要操控的UI节点就不使用标签。

  接着,可以使用以下两种方式管理所有节点:

  方法1:建立字典

    //存储一下需要用到的UIGO,以防止每次都去所有节点查找一遍
    private Dictionary<string, GameObject> uiItem;

  然后在面板初始化的时候,把所有的节点都加入到字典中去。(详见下面的初始化工具代码)

  方法2:直接拖进面板

    如果节点不多的话,可以建立一批public的GameObject,简单粗暴地将相应的UI节点直接拖进面板,例如:

        [Header("MENUS")]
        [Tooltip("The Menu for when the MAIN menu buttons")]
        public GameObject mainMenu;
        [Tooltip("THe first list of buttons")]
        public GameObject firstMenu;
        [Tooltip("The Menu for when the PLAY button is clicked")]
        public GameObject playMenu;
        [Tooltip("The Menu for when the EXIT button is clicked")]
        public GameObject exitMenu;
        [Tooltip("Optional 4th Menu")]
        public GameObject extrasMenu;

  然后一个一个对应拖进去

以下详细介绍一下UIBase.cs实现的过程:

  2.  UIBase包含了以下的工具

  (1)初始化——需要实现的工作有:遍历UI节点并将它们放入字典管理、给“UIGO”标签的节点挂上EventTrigger组件、给根节点(Canvas)挂上CanvasGroup组件。

    private Dictionary<string, GameObject> uiItem;  //字典用于存储UI节点

    public virtual void InitPanel(UnityAction action=null)
    {
        uiItem= new Dictionary<string, GameObject>();//实例化字典对象
        List<Transform> list= new List<Transform>(); //建立一个列表用于存储节点
        FindChild(transform,list);  
        //使用自定义的FindChild方法遍历当前节点以下的所有子节点,并存入list

        foreach (var item in list)
        {
            if(item.CompareTag("UIEvent"))  //判断列表中找到的是否有UIEvent的标签
            {//有的话就添加EventTrigger组件
                var trigger=item.gameObject.AddComponent<EventTrigger>();
                if (trigger.triggers.Count == 0)
                {//新建的EventTrigger列表为空,添加一个新Entry列表
                    trigger.triggers=new List<EventTrigger.Entry>(); 
                }
                uiItem.Add(item.name, item.gameObject); //并且把这个节点添加到字典中
            }
            if (item.CompareTag("UIGO"))
            {//如果UI节点的标签是UIGO,也放入到字典中
                uiItem.Add(item. name, item.gameObject);
            }
        }
        canvasGroup = gameObject.GetComponent<CanvasGroup>();
        //获取UI根节点的CanvasGroup,以便于控制实现面板慢慢显现的特效
        action?.Invoke();  //如果有回调的话回调
    }

  其中,遍历子节点的方法可以归纳称为一个小工具:

    //一个查找子物体的工具,从当前节点开始找
    private void FindChild(Transform father,List<Transform> list)
    {
        if(father.childCount> 0)
        {
            for(int i=0;i<father.childCount;i++)
            {
                list.Add(father.GetChild(i));
                FindChild(father.GetChild(i),list);
            }
        }
        return;
    }

  (2)显示面板——如果不使用DoTween,而是直接显示出来

    //显示面板
    public virtual void Show(UnityAction action=null)
    {
        gameObject.SetActive(true);  //节点激活
        action?.Invoke();
    }

    如果使用DoTween做一个渐显的小动画,那么Show工具写成下面:

    //显示面板
    public virtual void Show(UnityAction action=null)
    {
        gameObject.SetActive(true);  //节点激活
        switch(showType) //显示的方式ShowType定义为一个枚举数据
        {
            case ShowType.Normal:   
                action?.Invoke();
                break;
            case ShowType.Fade:
            {
                if (canvasGroup == null)
                    { canvasGroup = gameObject.AddComponent<CanvasGroup>(); }
                canvasGroup.interactable = false;  //还没显示完全时不允许交互
                canvasGroup.DOFade(0f, 0f); //DoTween插件,控制Alfa值,透明度变成0,1s时间
                canvasGroup.DOFade(1f, 1.5f).SetEase(Ease.OutExpo).OnComplete(()=>
                {
                    action?.Invoke();
                    canvasGroup.interactable = true;  // 可以交互
                });  //1.5s内按照OutExpo动画曲线显现,完成后回调
            }
                break;
        }
    }   

 其中显示方式ShowType,归纳成一个枚举数:

public enum ShowType
{
    Normal, Fade, Mask      //直接显示,渐显效果,遮罩
}

  (3)隐藏面板——结构与显示面板相似,为了节省篇幅,这里就不使用DoTween了,如果需要使用DoTween,可以把上面的显示面板代码复制修改一下

    //隐藏
    public virtual void Hide(UnityAction action=null)
    {
      action?.Invoke();
      gameObject.SetActive(false);
    }

  (4)获取组件——UI组件类型繁多,所以使用泛型方法来获取组件

    protected T GetComponent<T>(string name) where T : MonoBehaviour
    {
        if (!uiItem.ContainsKey(name)) return null;  //如果没有这个组件就返回空
        return uiItem[name].GetComponent<T>();
    }

  (5)给控件添加EventTrigger组件、注册事件——在上面已经说明过方法了

    public void AddEventTrigger(string controlName,EventTriggerType type,
        UnityAction<BaseEventData> callBack)
    {
        //从字典中获取控件,并添加EventTrigger组件
        if(!uiItem.ContainsKey(controlName)) return;
        if (uiItem[controlName].gameObject.GetComponent<EventTrigger>()==null)
            uiItem[controlName].AddComponent<EventTrigger>();
        //添加Entry、监听、回调
        EventTrigger.Entry entry = new EventTrigger.Entry();
        entry.callback = new EventTrigger.TriggerEvent();
        entry.callback.AddListener(callBack);  
        entry.eventID = type;
        uiItem[controlName].GetComponent<EventTrigger>().triggers.Add(entry);
    }

  以上这是总的UI面板管理工具,具体到每个UI面板,如主面板Canvas_Main、退出面板Canv_EXIT,有些游戏项目中还有背包面板、排行榜面板等等,是需要根据不同情况重写上面这些工具。下面就以主面板为例,写一下主面板管理的脚本MainUi.cs

建立分面板的管理工具——以主面板MainUi为例

  对于一个分面板来说,需要做的工作有:重写初始化工具、显示工具等;在关键节点上添加组件、事件和回调;获取重要节点的组件,比如图片、文字等组件,以备后续控制等等。

public class MainUI : UITools
{//针对MainUI节点的工具
    
    private TMP_Text IntroText;  // 获取一个Text控件以便于输出文字

    private GameObject Panel_EXTRAS;  //获取一个隐藏的面板

    public override void Init(UnityAction action = null) //重写UITools的Init()
    {
        base.Init(action);   
        //给Button_Play按钮添加一个PointerClick事件和回调
        AddEventTrigger("Button_Play", EventTriggerType.PointerClick, OnEventStart);
        Panel_EXTRAS = GetGameObject("EXTRAS"); //获取EXTRAS节点
        IntroText = GetComponent<TMP_Text>("IntroText");  //获取文字节点
    }

    public override void Show(UnityAction action = null)
    {//重写Show工具
        base.Show(action); 
        IntroText.text = "这是Main面板"; 
    }

    private void OnEventStart(BaseEventData data)
    {
        Hide(() =>    //按下Button_Play按钮,隐藏主面板,显示EXTRAS面板
        {
            UIManager.Instance.ShowPanel<EXTRASUI>("EXTRASUI", "EXTRASUI"); 
        });
    }
}

  以上就是主面板MainUi需要用到的工具,使用到了UIManager的显示面板ShowPanel,可以参照下一篇的UIManager的定义。

  其他的面板管理都可以参照此例,比如上面需要显示的EXTRAS面板,还需要有内容图片的排序工具,就可以在EXTRASUI.cs中定义。

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

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

相关文章

将conda环境导入pycharm教程(史上最详细版)

一个不知名大学生&#xff0c;江湖人称菜狗 original author: Jacky LiEmail : 3435673055qq.com Time of completion&#xff1a;2023.6.15 Last edited: 2023.6.15 目录 将conda环境导入pycharm教程&#xff08;史上最详细版&#xff09; 步骤一&#xff1a;打开你的pychar…

Esxi直通A40显卡给ubuntu20.4系统驱动安装过程记录

Esxi直通A40显卡给ubuntu20.4系统驱动安装过程记录 背景描述 PowerEdge R750&#xff08;esxi虚拟化&#xff09; 服务器已有一张T4显卡&#xff0c;后期新增一张A40显卡&#xff0c;开一台ubuntu20.4系统直通A40显卡无法开机&#xff01; 开机问题解决后安装显卡驱动也各种报…

可防撞抗震的海格里斯HEGERLS四向穿梭车立体库货架系统

随着经济的高速发展以及科学技术的不断进步&#xff0c;现代仓储和物流行业的发展都有了质的飞跃&#xff0c;技术融入到仓储的研发与生产中&#xff0c;促进了自动化仓储设备的出现。提到自动化仓储设备&#xff0c;那就无法忽视智能搬运机器人四向穿梭车&#xff0c;四向穿梭…

【Spring学习之生命周期】什么是生命周期?什么是作用域?了解六种作用域

前言&#xff1a; &#x1f49e;&#x1f49e;从前⾯的课程我们可以看出 Spring 是⽤来读取和存储 Bean&#xff0c;因此在 Spring 中 Bean 是最核⼼的操作资源&#xff0c;所以接下来我们深⼊学习⼀下 Bean 对象。 前路漫漫&#xff0c;希望大家坚持下去&#xff0c;不忘初心&…

让你不再疑惑如何转换音频格式

你是否曾经遇到过这样的问题&#xff1f;你有一些wav格式的音频文件&#xff0c;但是它们不能在你的设备上播放&#xff0c;或者你需要将它们转换为其他格式以便更好地编辑和分享。别担心&#xff0c;转换wav格式并不是一件麻烦的事情。如果你还不知道wav格式怎么转换的话&…

今天面了个阿里拿27K出来的测试,真是砂纸擦屁股,给我露了一手啊

2023年春招已经结束&#xff0c;很多小伙伴收获不错&#xff0c;拿到了心仪的 offer。 各大论坛和社区里也看见不少小伙伴慷慨地分享了常见的面试题和八股文&#xff0c;为此咱这里也统一做一次大整理和大归类&#xff0c;这也算是划重点了。 俗话说得好&#xff0c;他山之石…

如何判断测量所得的CSI是视距还是非视距

1、视距&#xff08;LOS&#xff09;传播 无线电波沿直线传播的方式称为视距传播。 2、非视距&#xff08;NLOS&#xff09;传播 当CSI接收机与基站(BS)之间的直射路径被障碍物挡住后&#xff0c;无线电波只能在经过反射和衍射后到达接收端&#xff0c;此时测量到的数据&…

由于找不到msvcp120.dll怎么办,msvcp120.dll一键修复方法

运行软件程序或游戏&#xff0c;提示由于找不到msvcp120.dll&#xff0c;遇到这种问题要怎么办呢&#xff1f;一般都是计算机系统的dll动态链接库损坏或者文件丢失&#xff0c;不用慌&#xff0c;这个只要修复一下就可以&#xff0c;下面小编就一一道来&#xff0c;还可以实现一…

PMP证书没过期的同学吃香了,直接对标CSPM国标证书二级

2021年10月&#xff0c;中共中央、国务院发布的《国家标准化发展纲要》明确提出构建多层次从业人员培养培训体系&#xff0c;开展专业人才培养培训和国家质量基础设施综合教育。建立健全人才的职业能力评价和激励机制。由中国标准化协会&#xff08;CAS&#xff09;组织开展的项…

使用dmhs veri手动比对ORACLE同步到DM数据

使用dmhs veri手动比对ORACLE同步到DM数据 veri介绍 在进行数据库数据的实时同步的时候&#xff0c;需要了解同步的结果是否正确&#xff0c;因此需要有数据对比工具进行数据的对比&#xff0c;并生成详细的对比报告&#xff0c;提供用户参考。对比工具仅仅生成报告&#xff…

【OpenMMLab】AI实战营第二期Day10:底层视觉与MMEditing

Summary 本课程包含底层视觉和MMEditing两个部分。第一部分介绍图像超分、深度学习和网络训练的相关算法&#xff0c;第二部分介绍超像素卷积、无监督学习、卷积网络和空间注意机制&#xff0c;以及这些算法在视觉框架中的实践应用。 Highlights &#x1f4f7;介绍计算机视觉…

ChatGPT 3.5/4 双双升级:更长,更便宜,更开放,更可控

OpenAI 今年早些时候发布了 gpt-3.5-turbo 和 gpt-4&#xff0c;并且在短短几个月内&#xff0c;开发者在这些模型上开发了很多令人印象深刻的应用。 6月13日&#xff0c; OpenAI 官宣了版本更新的内容&#xff1a; Chat Completions API 中新增了函数调用功能。更可控的 gpt-4…

【有奖体验】叮!你有一张 3D 卡通头像请查收

立即体验基于函数计算部署【图生图】一键部署 3D 卡通风格模型&#xff1a;https://developer.aliyun.com/topic/aigc_fc 人工智能生成内容&#xff08;Artificial Intelligence Generated Content&#xff0c;简称 AIGC&#xff09;是当下最火的概念之一。AIGC 被认为是继专业…

MFC .rc文件解析(EXE属性详细信息添加)

文章目录 Windows 资源文件(.rc文件)资源(Resources)类型从文件导入的&#xff08;BITMAP&#xff0c;ICON&#xff0c;HTML&#xff0c;FONT&#xff0c;CURSOR 等&#xff09;对话框资源类型&#xff1a;&#xff08;DIALOG&#xff0c;DIALOGEX 等&#xff09;菜单资源类型字…

【Java项目】使用Nacos实现动态线程池技术以及Nacos配置文件更新监听事件

文章目录 项目源码线程池概念ThreadPoolExecutor介绍Nacos实现对Nacos配置文件更新的事件监听机制定时通知功能邮件发送通知功能开始测试 项目源码 真诚的希望能给我项目一个stars&#xff01;&#xff01;&#xff01; 项目源码 线程池概念 线程池&#xff08;Thread Pool&…

Megatron-LM GPT2

内容 使用原始 Megatron-LM 训练 GPT-2 训练数据设置运行未修改的 Megatron-LM GPT2 模型启用 DeepSpeed 参数解析初始化和训练 初始化使用训练 API 前向传播反向传播更新模型参数损失缩放检查点保存和加载DeepSpeed 激活检查点&#xff08;可选&#xff09;训练脚本使用 GPT-…

拆分代码 + 预加载,减少首屏资源,提升首屏性能及应用体验

route-resource-preload 组件懒加载可以极大地提升我们的应用首屏加载体验, 但我们在进行组件资源拆包后&#xff0c;一旦加载某个组件资源出现以上时间过长的情况&#xff0c;则会出现视图无法正常渲染的问题&#xff08;导致页面白屏/组件出不来/交互卡顿等情况&#xff09;。…

Pytest教程__钩子方法setup、teardown、setup_class、teardown_class(8)

pytest跳过用例执行的用法与unittest跳过用例大致相同。 pytest跳过用例的方法如下&#xff1a; pytest.mark.skip(reason)&#xff1a;无条件用例。reason是跳过原因&#xff0c;下同。pytest.mark.skipIf(condition, reason)&#xff1a;condition为True时跳过用例。 pyte…

代码随想录算法训练营第五十八天|739. 每日温度|496.下一个更大元素 I

LeetCode739. 每日温度 基本思路&#xff1a;什么时候使用单调栈呢&#xff1f;通常是一维数组&#xff0c;要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置&#xff0c;此时我们就要想到可以用单调栈了。时间复杂度为O(n)。例如本题其实就是找找到一个元素右…

【发电厂】发电厂模型验证应用于电网事件在线性能监测【相量测量单元 (PMU) 数据对电网事件的在线性能监控】研究(MatlabSimulink实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…