【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()
    {
        // 初始化UI
        UIInit();
        // 初始化参数
        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之UGUIUGUIUnity的UI系统UGUI全解析,从UGUI的基础控件开始讲起,然后将UGUI的原理,UGUI的使用全面教学。
Unity3D之读取数据文件读取使用Unity3D读取txt文档、json文档、xml文档、csv文档、Excel文档。
Unity3D之数据集合数据集合数组集合:数组、List、字典、堆栈、链表等数据集合知识分享。
Unity3D之VR/AR(虚拟仿真)开发虚拟仿真总结博主工作常见的虚拟仿真需求进行案例讲解。
Unity3D之插件插件主要分享在Unity开发中用到的一些插件使用方法,插件介绍等
Unity3D之日常开发日常记录主要是博主日常开发中用到的,用到的方法技巧,开发思路,代码分享等
Unity3D之日常BUG日常记录记录在使用Unity3D编辑器开发项目过程中,遇到的BUG和坑,让后来人可以有些参考。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

12.1 主成分分析原理(PCA)

主成分分析步骤如下&#xff1a; 设有条维数据 1. 将原始数据按列组成行列矩阵 &#xff1b; 2. 将矩阵 的每一行进行零均值化&#xff1b; 3. 求出协方差矩阵&#xff1b; 4. 求出协方差矩阵的特征值及对应的特征向量&#xff1b; 5. 将特征向量按对应特征值大小从上到…

富文本编辑器CKEditor4简单使用-04(跟源码设置image2插件图片的默认宽高等相关配置)

富文本编辑器CKEditor4简单使用-04&#xff08;跟源码设置image2插件图片的默认宽高等相关配置&#xff09; 1. 前言1.1 CKEditor4快速上手 2. CKEditor4的一般配置2.1 工具栏相关2.2 插件相关2.3 设置界面宽高等 3. CKEditor4的图片相关配置3.1 关于增强的图像插件的必要配置3…

洛谷 P3817 小A的糖果

题目描述 小 A 有 n 个糖果盒&#xff0c;第 i 个盒中有 a【i​】 颗糖果。 小 A 每次可以从其中一盒糖果中吃掉一颗&#xff0c;他想知道&#xff0c;要让任意两个相邻的盒子中糖的个数之和都不大于 x&#xff0c;至少得吃掉几颗糖。 输入格式 输入的第一行是两个用空格隔…

nop-entropy可逆计算入门(1)

第1步&#xff1a;从大佬的gitee&#xff1a;https://gitee.com/canonical-entropy/nop-entropy下载源码&#xff0c;进行本地编译&#xff0c;具体编译看项目下的readme,想偷懒的可以下载我编译后的jar&#xff0c;放到自己的maven仓库 https://pan.baidu.com/s/1p9MOh40MJ2m…

unity 拖入文件 窗口大小

目录 unity 拖入文件插件 设置窗口大小 unity 拖入文件插件 GitHub - Bunny83/UnityWindowsFileDrag-Drop: Adds file drag and drop support for Unity standalong builds on windows. 设置窗口大小 file build

【kubernetes】集群网络(二):Flannel的VxLan、Host-GW模式

文章目录 1 Pod的IP地址的分配2 CNI3 Flannel3.1 Flannel的安装3.2 VxLan3.3 Host-GW 4 总结 1 Pod的IP地址的分配 当节点上只安装了docker&#xff0c;则会用veth pairdocker0实现单个节点上容器之间的通信&#xff0c;并且这些容器都在同一个IP段&#xff0c;如果不修改&…

挑战杯 LSTM的预测算法 - 股票预测 天气预测 房价预测

0 简介 今天学长向大家介绍LSTM基础 基于LSTM的预测算法 - 股票预测 天气预测 房价预测 这是一个较为新颖的竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/postgraduate 1 基于 Ke…

STM32F407移植OpenHarmony笔记8

继上一篇笔记&#xff0c;成功开启了littlefs文件系统&#xff0c;能读写FLASH上的文件了。 今天继续研究网络功能&#xff0c;让控制台的ping命令能工作。 轻量级系统使用的是liteos_m内核lwip协议栈实现网络功能&#xff0c;需要进行配置开启lwip支持。 lwip的移植分为两部分…

8、应急响应-战前溯源反制主机蜜罐系统HFishHIDSElkeidWazuh

用途&#xff1a;个人学习笔记&#xff0c;欢迎指正 目录 背景&#xff1a; 一、潮源反制-平台部署-蜜罐-Hfish 二、溯源反制-平台部署-HIDS-Wazuh 三、溯源反制-平台部署-HlDS-Elkeid-hub 背景&#xff1a; 攻击者对服务器存在着各种威胁行为&#xff0c;作为安全人员&am…

SpringBoot security 安全认证(二)——登录拦截器

本节内容&#xff1a;实现登录拦截器&#xff0c;除了登录接口之外所有接口访问都要携带Token&#xff0c;并且对Token合法性进行验证&#xff0c;实现登录状态的保持。 核心内容&#xff1a; 1、要实现登录拦截器&#xff0c;从Request请求中获取token&#xff0c;从缓存中获…

【自然语言处理】P2 PyTorch 基础 - 张量

目录 安装 PyTorch张量创建张量操作张量索引、切片、联合操作 CUDA张量 本系列博文我们将使用 PyTorch 来实现深度学习模型等。PyTorch 是一个开源的、社区驱动的深度学习框架。拥有强大的工具和库生态系统&#xff0c;包含 TorchVision&#xff08;用于图像处理&#xff09;、…

2024 IC FPGA 岗位 校招面试记录

引言 各位看到这篇文章时&#xff0c;24届校招招聘已经渐进尾声了。 在这里记录一下自己所有面试&#xff08;除了时间过短或者没啥干货的一些研究所外&#xff0c;如中电55所&#xff08;南京&#xff09;&#xff0c;航天804所&#xff08;上海&#xff09;&#xff09;的经…

图像去噪——SpatiallyAdaptiveSSID网络推理测试(详细图文教程)

SpatiallyAdaptiveSSID 是一种有效的图像去噪方法&#xff0c;它通过自适应地处理不同区域的噪声&#xff0c;能够在保持图像细节的同时&#xff0c;有效地去除噪声。 目录 一、SpatiallyAdaptiveSSID网络简介二、源码包准备2.1 测试集2.2 模型权重文件 三、测试环境四、推理测…

【Python-环境搭建】

Python-环境搭建 ▼ Python安装► 进入Python官网 地址如下 [Python官网](https://www.python.org/)► Python安装向导对话框► 测试是否安装成功 ▼ PyCharm 安装► Pycharm的下载和安装 ▼► 开始在 Windows 上使用 Python&#xff08;初学者&#xff09; ▼ Python安装 ► …

Web3生态系统:构建去中心化的数字社会

随着科技的飞速发展&#xff0c;我们正处在迈向数字未来的道路上&#xff0c;而Web3生态系统则成为这一变革的中心。不仅仅是技术的演进&#xff0c;Web3代表着对传统互联网体系的颠覆&#xff0c;致力于构建一个去中心化的数字社会。本文将深入探讨Web3的核心特征、对金融、社…

2024年美赛B题思路分析 - 搜索潜水器

# 1 赛题 问题B&#xff1a;搜索潜水器 总部位于希腊的小型海上巡航潜艇&#xff08;MCMS&#xff09;公司&#xff0c;制造能够将人类运送到海洋最深处的潜水器。潜水器被移动到该位置&#xff0c;并不受主船的束缚。MCMS现在希望用他们的潜水器带游客在爱奥尼亚海底探险&…

MySQL中where和having的区别

前言 数据库中的 WHERE 和 HAVING 子句在 SQL 查询中扮演着关键的角色&#xff0c;帮助我们有效地筛选和过滤数据。这两个子句虽然都用于限定结果集&#xff0c;但它们的应用场景和操作对象存在明显的区别。在理解和运用这两个子句的过程中&#xff0c;我们能够更灵活地进行数据…

MySql主从同步,同步SQL_ERROR 1032解决办法

1.登录从库 mysql -u root -p 2.输入命令查看状态 SHOW SLAVE STATUS\G; 3.找到对应的错误数据位置 Slave_IO_Running: YesSlave_SQL_Running: NoReplicate_Do_DB: app_push_centerReplicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Tabl…

仰暮计划|“现在不一样了,时代发展了,年轻人都有自己想做的事了,也不急着结婚生育了,我觉得挺好的”

仰暮计划|“现在不一样了&#xff0c;时代发展了&#xff0c;年轻人都有自己想做的事了&#xff0c;也不急着结婚生孩子了&#xff0c;我觉得挺好的” 忆暖行动 口述人&#xff1a;赵凤云&#xff08;女&#xff09; 整理人&#xff1a;王鑫雨 河南财经政法大学 202134060501 …

欧拉函数及其代码实现

欧拉函数&#xff1a; 欧拉函数定义&#xff1a;欧拉函数是指对于一个正整数 n &#xff0c;小于等于 n 且和 n 互质的正整数&#xff08;包括 1&#xff09;的个数&#xff0c;记作 φ(n)。 例如φ(8) 4&#xff0c;因为1,3,5,7均和8互质。 性质&#xff1a; 当 n 是质数…