【Unity3D小技巧】Unity3D中UI控制解决方案
推荐阅读
- CSDN主页
- GitHub开源地址
- Unity3D插件分享
- 简书地址
- 我的个人博客
大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。
一、前言
在开发中总是会控制UI界面,如何优雅的控制UI界面是每一个Unity3D程序员的必修课。
这篇文章就总结了一下博主在实际开发中用到的几种控制UI的方式,分享出来以供批评指正。
在文章的最后,也根据UI控制做了一些延展,比如说:
- 控制UI顺序
- 控制UI层级
- 控制初始化的先后顺序
- 显示隐藏的堆栈
二、正文
2-1、讨论UI控制的解决方案
先说一下痛点吧,隐藏UI面板很简单,xx.SetActive(false);就行,但是这个管理的脚本放在哪里是个问题。
因为这个挂载的对象一旦隐藏,那么这个脚本就失灵了,所以一般不能挂载在UI面板自己身上,因为一旦隐藏就不管用了。
但是UI统一管理耦合性太高,不适合组件开发,但是也是一种控制方法。
挂载在UI面板自己身上,就需要一些技巧,避开隐藏自身这种行为。
由此为基础,有下面几种方案的讨论。
2-1-1、用一个脚本统一管理脚本的方式
实现方式
先搭建UI,然后新建一个对象挂载控制UI的脚本,然后这个脚本里面控制所有的UI事件。
例子
效果图:


代码参考:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class UIControl : MonoBehaviour
{public GameObject Panel1;public Button Btn1;public GameObject Panel2;public Text TextTitle;public Text TextContent;public GameObject Panel3;public GameObject Panel4;void Start(){// 按钮绑定Btn1.onClick.AddListener(ClickSure);}void ClickSure(){}public void ShowPanel(){Panel1.SetActive(true);}
}
用这个脚本去控制所有的对象,保存隐藏显示、文字赋值、按钮绑定事件等。
优缺点
优点:
脚本一般都在一个独立对象上,脚本容易找。控制显示隐藏不容易报NULL对象错误。
缺点:
耦合性太高,所有的UI对象都在一个脚本中,脚本代码比较拥杂,并且无法独立出来形成组件进行复用。
2-1-2、面板自身挂载脚本,通过控制所有子对象来隐藏面板
实现方式
UI自身带有控制的脚本,通过控制所有子对象来实现隐藏或显示。
例子
效果图:

优缺点
优点:组件化开发,可以形成预制体复用,不必隐藏面板。
缺点:需要获取所有子对象,并且父节点身上不能添加Image,不然隐藏所有子对象也不行。
2-1-3、面板自身挂载脚本,通过控制UI界面缩放来隐藏面板
实现方式
UI界面挂载脚本,控制UI界面的缩放为0即可隐藏脚本,算是视觉隐藏,但是实际没有隐藏。
例子
效果图:

优缺点
优点:不必获取子对象,使用缩放控制。
缺点:不确定面板是否要显示,没法控制显示顺序。
2-1-4、面板自身挂载脚本,通过控制UI子节点来隐藏面板
实现方式
算是第一种和第二种方法的一种优化和升级。
在UI界面下面再设置一个节点用来控制所有的UI对象,随意控制隐藏和显示都没有问题,也不用获取所有的子对象,非常好用。
例子
效果图:

优缺点
优点:控制子对象,不用直接控制UI界面,避免脚本禁用情况,方便管理,也可以默认隐藏,更加灵活。
缺点:搭建UI的时候需要按照一定的规则搭建。比如UI界面是根节点,下一个节点是控制UI界面隐藏和显示的节点,再下面才是真正的UI搭建。
2-2、方法改良及可行性演示
2-1小结分析的几种解决方案都有优点和缺点,再次基础上,总结了一个比较完善的改良型方案。
UI面板自身挂载脚本,下面一个子节点是所有UI的父节点,也就是:

这样的话,一个UI界面的父节点是固定的,然后子节点用同一个名字方便脚本控制。
代码参考:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Diagnostics;
using UnityEngine.UI;public class Panel3Logic : MonoBehaviour
{GameObject currentObj;Button BtnSure;Action endAction;void Start(){currentObj = transform.Find("UIControl").gameObject;currentObj.SetActive(false);BtnSure = currentObj.transform.Find("BtnSure").GetComponent<Button>();BtnSure.onClick.AddListener(BtnSureEvent);}/// <summary>/// 显示隐藏面板/// </summary>/// <param name="ison"></param>void ShowInfo(bool ison){currentObj.SetActive(ison);}/// <summary>/// 设置委托函数/// </summary>/// <param name="ison"></param>/// <param name="endAction"></param>void ShowInfo(bool ison, Action endAction){currentObj.SetActive(ison);this.endAction = endAction;}/// <summary>/// 点击确定的时候,关闭面板,并且执行委托函数/// </summary>void BtnSureEvent(){currentObj.SetActive(false);endAction?.Invoke();}
}
2-3、延展内容
这一节就将UI控制解决方案再做一下延展,包括:
- 控制初始化的先后顺序
- 控制UI层级和顺序
- 显示隐藏的堆栈
新建一个UI基类UIBase.cs,双击编辑代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;public class UIBase : MonoBehaviour
{/// <summary>/// 初始化顺序/// </summary>public int StartOrder;/// <summary>/// 层级顺序/// </summary>public int LayerOrder;/// <summary>/// 唯一标识符/// </summary>[HideInInspector]public int UniqueID;public virtual void OnStart() { }public virtual void ShowInfo(bool ison) { }
}
UI界面控制UI继承与这个基类,比如说Panel1Logic.cs,编辑代码:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class Panel1Logic : MonoBehaviour
{GameObject currentObj;Button BtnSure;Action endAction;/// <summary>/// 初始化顺序/// </summary>public int StartOrder;/// <summary>/// 层级顺序/// </summary>public int LayerOrder;/// <summary>/// 唯一标识符/// </summary>public int UniqueID;public void OnStart(){currentObj = transform.Find("UIControl").gameObject;currentObj.SetActive(false);BtnSure = currentObj.transform.Find("BtnSure").GetComponent<Button>();BtnSure.onClick.AddListener(BtnSureEvent);}/// <summary>/// 显示隐藏面板/// </summary>/// <param name="ison"></param>public void ShowInfo(bool ison){currentObj.SetActive(ison);}/// <summary>/// 设置委托函数/// </summary>/// <param name="ison"></param>/// <param name="endAction"></param>public void ShowInfo(bool ison, Action endAction){currentObj.SetActive(ison);this.endAction = endAction;}/// <summary>/// 点击确定的时候,关闭面板,并且执行委托函数/// </summary>void BtnSureEvent(){currentObj.SetActive(false);endAction?.Invoke();}
}
UI控制脚本UIControl.cs,编辑代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class UIControl : MonoBehaviour
{public List<UIBase> UIList;// 使用栈的后进先出的特性,实现UI的后显示先隐藏的功能Stack<GameObject> uiQueue;void Start(){// 初始化UIUIInit();// 初始化参数uiQueue = new Stack<GameObject>();}void UIInit(){// 排序UIList.Sort((x, y) => x.StartOrder.CompareTo(y.StartOrder));// 设置初始化顺序for (int i = 0; i < UIList.Count; i++){Debug.Log(UIList[i].StartOrder);UIList[i].OnStart();UIList[i].UniqueID = 1000 + i;}// 排序UIList.Sort((x, y) => x.LayerOrder.CompareTo(y.LayerOrder));// 设置层级顺序for (int i = 0; i < UIList.Count; i++){Debug.Log(UIList[i].LayerOrder);UIList[i].transform.SetSiblingIndex(UIList[i].LayerOrder);}}/// <summary>/// 显示UI/// </summary>/// <param name="UniqueID"></param>public void ShowPanel(int UniqueID){UIBase uiObj = UIList.Find(value => value.UniqueID == UniqueID);if (uiObj != null){uiObj.ShowInfo(true);uiQueue.Push(uiObj.gameObject);}}/// <summary>/// 隐藏UI 适用于多个UI重叠 点击任意位置关闭UI的情况/// </summary>public void HidePanel(){GameObject ui = uiQueue.Pop();ui.GetComponent<UIBase>().ShowInfo(false);}
}
三、后记
如果觉得本篇文章有用别忘了点个关注,关注不迷路,持续分享更多Unity干货文章。
你的点赞就是对博主的支持,有问题记得留言:
博主主页有联系方式。
博主还有跟多宝藏文章等待你的发掘哦:
| 专栏 | 方向 | 简介 |
|---|---|---|
| Unity3D开发小游戏 | 小游戏开发教程 | 分享一些使用Unity3D引擎开发的小游戏,分享一些制作小游戏的教程。 |
| Unity3D从入门到进阶 | 入门 | 从自学Unity中获取灵感,总结从零开始学习Unity的路线,有C#和Unity的知识。 |
| Unity3D之UGUI | UGUI | Unity的UI系统UGUI全解析,从UGUI的基础控件开始讲起,然后将UGUI的原理,UGUI的使用全面教学。 |
| Unity3D之读取数据 | 文件读取 | 使用Unity3D读取txt文档、json文档、xml文档、csv文档、Excel文档。 |
| Unity3D之数据集合 | 数据集合 | 数组集合:数组、List、字典、堆栈、链表等数据集合知识分享。 |
| Unity3D之VR/AR(虚拟仿真)开发 | 虚拟仿真 | 总结博主工作常见的虚拟仿真需求进行案例讲解。 |
| Unity3D之插件 | 插件 | 主要分享在Unity开发中用到的一些插件使用方法,插件介绍等 |
| Unity3D之日常开发 | 日常记录 | 主要是博主日常开发中用到的,用到的方法技巧,开发思路,代码分享等 |
| Unity3D之日常BUG | 日常记录 | 记录在使用Unity3D编辑器开发项目过程中,遇到的BUG和坑,让后来人可以有些参考。 |
相关文章:
【Unity3D小技巧】Unity3D中UI控制解决方案
推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 在开发中总是会控制UI界面,如何优雅的控制UI界面是…...
【状态管理一】概览:状态使用、状态分类、状态具体使用
文章目录 一. 状态使用概览二. 状态的数据类型1. 算子层面2. 接口层面2.1. UML与所有状态类型介绍2.2. 内部状态:InternalKvState 将知识与实际的应用场景、设计背景关联起来,这是学以致用、刨根问底知识的一种直接方式。 本文介绍 状态数据管理&#x…...
SQL--多表查询
我们之前在讲解SQL语句的时候,讲解了DQL语句,也就是数据查询语句,但是之前讲解的查询都是单 表查询,而本章节我们要学习的则是多表查询操作,主要从以下几个方面进行讲解。 多表关系 项目开发中,在进行数据…...
多维时序 | Matlab实现CNN-RVM卷积神经网络结合相关向量机多变量时间序列预测
多维时序 | Matlab实现CNN-RVM卷积神经网络结合相关向量机多变量时间序列预测 目录 多维时序 | Matlab实现CNN-RVM卷积神经网络结合相关向量机多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现CNN-RVM卷积神经网络结合相关向量机多变量时间序…...
RK3568平台 安卓hal3适配usb camera
一.RK安卓hal3 camera框架 Camera hal3 在 android 框架中所处的位置如上图, 对上,主要实现 Framework 一整套 API 接口,响应其 控制命令,返回数据与控制参数结果。 对下, 主要是通 V4l2 框架实现与 kernel 的交互。3a…...
使用 Visual Studio Code 在远程计算机上调试 PostgreSQL
使用 Visual Studio Code 在远程计算机上调试 PostgreSQL 1. 概述 PostgreSQL 是一个功能强大的开源关系数据库管理系统,适用于各种应用程序。在开发过程中,调试 PostgreSQL 对于识别和解决问题至关重要。在本博客中,我们将手把手教你使用客…...
javascript设计模式之建造者
工厂模式不关心过程,只关心结果,这与建造者相反,建造者更关心的是过程, 这里我们创建一个基类,其拥有技能跟爱好两个属性,还有两个实例方法用来获取技能跟爱好 // 基类 let Human function (param {}) …...
安擎科技携手华为云区块链共同打造安全天空
当前,低空经济崛起,无人机多并发、混合运行时引发的网络信息安全、空域安全问题已成行业首要课题。 在2024年1月正式实施的《民用无人驾驶航空器运行安全管理规则》(CCAR-92)第549条中规定,“无人驾驶航空器航行服务提…...
学习数据结构的第一天
结构体 如何定义结构体 1、先定义结构体类型,再定义结构体类型变量 struct student/定义学生结构体类型/ { long number; char name[20]; char sex; int age; float score[3];/三科考试成绩/ }2、定义结构体类型同时定义结构体类型变量 struct student/定义学生结…...
5.electron之主进程起一个本地服务
如果可以实现记得点赞分享,谢谢老铁~ Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 Electron 将 Chromium 和 Node.js 嵌入到了一个二进制文件中,因此它允许你仅需一个代码仓库,就可以撰写支持 Windows、…...
爬取58二手房并用SVR模型拟合
目录 一、前言 二、爬虫与数据处理 三、模型 一、前言 爬取数据仅用于练习和学习。本文运用二手房规格sepc(如3室2厅1卫)和二手房面积area预测二手房价格price,只是练习和学习,不代表任何实际意义。 二、爬虫与数据处理 import requests import cha…...
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之RichText组件
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之RichText组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、RichText组件 鸿蒙(HarmonyOS)富文本组件,…...
7.electron之渲染线程发送事件,主进程监听事件
如果可以实现记得点赞分享,谢谢老铁~ Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 Electron 将 Chromium 和 Node.js 嵌入到了一个二进制文件中,因此它允许你仅需一个代码仓库,就可以撰写支持 Windows、…...
thinkphp6入门(19)-- 中间件向控制器传参
可以通过给请求对象赋值的方式传参给控制器(或者其它地方),例如 <?phpnamespace app\middleware;class Hello {public function handle($request, \Closure $next){$request->hello ThinkPHP;return $next($request);} } 然后在控制…...
Flink Format系列(2)-CSV
Flink的csv格式支持读和写csv格式的数据,只需要指定 format csv,下面以kafka为例。 CREATE TABLE user_behavior (user_id BIGINT,item_id BIGINT,category_id BIGINT,behavior STRING,ts TIMESTAMP(3) ) WITH (connector kafka,topic user_behavior…...
Spring Data Envers 数据审计实战2 - 自定义监听程序扩展审计字段及字段值
上篇讲述了如何在Spring项目中集成Spring Data Envers做数据审计和历史版本查看功能。 之前演示的是业务表中已有的字段进行审计,那么如果我们想扩展审计字段呢? 比如目前对员工表加入了Audited审计,员工表有个字段为dept_id,为…...
一个 SpringBoot 项目能同时处理多少请求?
目录 1 问题分析 2 Demo 3 答案 4 怎么来的? 5 标准答案及影响参数一Tomcat配置 6 影响参数二 Web容器 7 影响参数三 Async 1 问题分析 一个 SpringBoot 项目能同时处理多少请求? 不知道你听到这个问题之后的第一反应是什么? 我大概…...
计算机网络——网络
计算机网络——网络 小程一言专栏链接: [link](http://t.csdnimg.cn/ZUTXU)前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家, [跳转到网站](https://www.captainbed.cn/qianqiu) 无线网络和移动网…...
C语言探索:选择排序的实现与解读
当我们需要对一组数据进行排序时,选择排序(Selection Sort)是一种简单但效率较低的排序算法。它的基本思想是每次从未排序的数据中选择最小(或最大)的元素,然后将其放置在已排序序列的末尾。通过重复这个过…...
Golang 学习(二)进阶使用
二、进阶使用 性能提升——协程 GoRoutine go f();一个 Go 线程上,可以起多个协程(有独立的栈空间、共享程序堆空间、调度由用户控制)主线程是一个物理线程,直接作用在 cpu 上的。是重量级的,非常耗费 cpu 资源。协…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
用鸿蒙HarmonyOS5实现中国象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...
