【Unity3D】UGUI实现层级菜单
发布日期:2021-06-30 11:38:43 浏览次数:2 分类:技术文章

本文共 23059 字,大约阅读时间需要 76 分钟。

一、前言

层级菜单在Unity中用到的并不多,主要是做分类的时候用的比较多,今天就给大家分享几个层级代码,扩充一下,写成插件也是不错的。

首先看一下效果吧:

1.
在这里插入图片描述
2.
在这里插入图片描述
3.
在这里插入图片描述
在这里插入图片描述
4.
在这里插入图片描述
5.
在这里插入图片描述

二、资源下载

源文件:

Github下载地址:

三、正文

第一种实现效果

在这里插入图片描述

实现原理:这个是用系统自带的UGUI Scroll View组件,脚本控制创建父物体,父物体身上挂载有初始化子物体的脚本
优缺点:
优点是实现简单,不需要多与的插件,代码量也不大,控制比较方便
缺点是只能实现两个层级的显示
实现过程:
1、新建一个Scrpll View
在这里插入图片描述
2、制作预制体
界面就这么设计就行:
在这里插入图片描述

名字改一下

Content:父节点容器
ParentMenu:父节点
TextParent:父节点文本
ChildMenu:子节点容器
item:子节点
TextChild:子节点文本
在这里插入图片描述
然后将父节点改名字叫parentMenu,做成预制体:
在这里插入图片描述
预制体放到Resources文件夹中:
在这里插入图片描述
将子物体也制作成预制体:
在这里插入图片描述
3、编写脚本ParentMenu.cs
这个脚本主要是作用是创建子物体:

using System.Collections;using UnityEngine;using UnityEngine.UI;public class ParentMenu : MonoBehaviour{
private GameObject childMenu;//子菜单的parent private RectTransform[] childs;//所有子菜单的rect private RectTransform itemRect;//子菜单的prefab private Vector3 offset;//单个子菜单的高度 private int count;//子菜单的个数 public bool isOpening {
get; private set; }//父菜单是否展开 public bool isCanClick {
get; set; }//父菜单是否可以点击 public void Init(RectTransform rect, int count) {
//找到子节点 childMenu = transform.Find("childMenu").gameObject; itemRect = rect; this.count = count; childs = new RectTransform[this.count]; offset = new Vector3(0, itemRect.rect.height); for (int i = 0; i < this.count; i++) {
childs[i] = Instantiate(itemRect, childMenu.transform); } childMenu.gameObject.SetActive(false); isOpening = false; isCanClick = true; GetComponent

4、编写脚本FoldableMenu.cs

这个脚本主要是为了创建父物体,以及控制折叠菜单

using System.Collections;using UnityEngine;using UnityEngine.UI;public class FoldableMenu : MonoBehaviour{
private RectTransform content;//父物体的parent private TextAsset textAsset;//所有菜单信息 private RectTransform parentRect;//父菜单的prefab private RectTransform[] parentArr;//所有父菜单的数组 private RectTransform childRect;//子菜单的prefab private Vector3 parentOffset;//单个父菜单的高度 private Vector3 childOffset;//单个父菜单的高度 private int[] cntArr;//所有父菜单拥有的子菜单个数 void Awake() {
Init(); } void Init() {
//获取到父节点 content = transform.Find("Viewport/Content").GetComponent
(); //获取到menuinfo里面的信息 3 3 4 4 5 5 textAsset = Resources.Load
("menuInfo"); //获取到父物体 设置父物体的高度 parentRect = Resources.Load
("parentMenu"); parentOffset = new Vector3(0, parentRect.rect.height); //获取到子物体 设置子物体的高度 childRect = Resources.Load
("item"); childOffset = new Vector3(0, childRect.rect.height); //分割字符串 info = 3 3 4 4 5 5 var info = textAsset.text.Split(',');//获取子菜单个数信息 //数组的长度 cntArr = new int[info.Length]; //父菜单的数组 parentArr = new RectTransform[info.Length]; //初始化content高度 宽度不变 高度是所有父物体的总长 content.sizeDelta = new Vector2(content.rect.width, parentArr.Length * parentRect.rect.height); //i = 6 for (int i = 0; i < cntArr.Length; i++) {
//创建服务器 parentArr[i] = Instantiate(parentRect, content.transform); //坐标为 上一个父物体的宽度 parentArr[i].localPosition -= i * parentOffset; //赋值 cntArr[i] = int.Parse(info[i]); //父物体上面加载子物体 子物体数量为3 3 4 4 5 5 parentArr[i].GetComponent
().Init(childRect, cntArr[i]); int j = i; //父物体上面的button绑定事件 parentArr[i].GetComponent

将这个脚本挂载到Scroll View上面:

在这里插入图片描述
运行,搞定!

第二种实现效果

在这里插入图片描述

实现原理:这个也是用UGUI做的,不一样的是不需要容器组件,主要是寻找父节点,然后保存父节点的信息,下一个节点以父节点为目标进行偏移,或者以父节点为目标做子节点
优缺点:
优点是代码清晰,可扩展性强,不需要设计UGUI
缺点结构比较简单,没有实现多层级的功能
实现过程:
1、创建预制体
在这里插入图片描述
结构比较简单,两个Image,箭头的图片带Button组件(可以下拉和合并)
然后将预制体放到Resources文件夹中:
在这里插入图片描述
2、编写PublicData.cs脚本
一个数据类

using UnityEngine;public class PublicData{
public static Transform parent; public static Vector2 currentPosition;}

3、编写脚本Options_Triangle.cs

初始化子节点的函数

using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;public class Options_Triangle : MonoBehaviour{
public Button triangle; public Image content; public List
children = new List
(); void Start() {
triangle.onClick.AddListener(() => {
if (triangle.transform.eulerAngles.z == 270) {
triangle.transform.eulerAngles = Vector3.zero; for (int i = 0; i < children.Count; i++) {
children[i].gameObject.SetActive(false); } } else {
triangle.transform.eulerAngles = new Vector3(0, 0, -90); for (int i = 0; i < children.Count; i++) {
children[i].gameObject.SetActive(true); } } }); }}

4、编写ClickEvent.cs

这是一个层级菜单的编辑功能的脚本

using UnityEngine;using UnityEngine.UI;public class ClickEvent : MonoBehaviour{
public Button add_options_t; public Button add_options; public Transform canvasParent; void Start() {
add_options_t.onClick.AddListener(() => {
if (PublicData.parent == null) {
PublicData.parent = Instantiate(Resources.Load
("Options_triangle")); PublicData.parent.transform.SetParent(canvasParent, false); PublicData.currentPosition = new Vector2(PublicData.parent.position.x, PublicData.parent.position.y); } else {
Transform option = Instantiate(Resources.Load
("Options_triangle")); option.transform.SetParent(PublicData.parent, false); option.transform.position = new Vector3(PublicData.currentPosition.x + 30, PublicData.currentPosition.y - 32, 0); PublicData.parent.GetComponent
().triangle.transform.eulerAngles = new Vector3(0, 0, -90); PublicData.parent.GetComponent
().children.Add(option); PublicData.parent = option; PublicData.currentPosition = new Vector2(PublicData.parent.position.x, PublicData.parent.position.y); } }); add_options.onClick.AddListener(() => {
if (PublicData.parent == null) {
return; } PublicData.parent.GetComponent
().triangle.transform.eulerAngles = new Vector3(0, 0, -90); Transform content = Instantiate(Resources.Load
("Options")); content.transform.SetParent(PublicData.parent, false); content.transform.position = new Vector3(PublicData.currentPosition.x + 16, PublicData.currentPosition.y - 32, 0); PublicData.parent.GetComponent
().children.Add(content); PublicData.currentPosition = new Vector2(content.position.x - 16, content.position.y); }); }}

OK。将ClickEvent脚本挂载在场景中的任一物体身上就可以了

第三种实现效果

在这里插入图片描述

实现原理:这个也是用UGUI做的,比较有特点的地方是没有使用一行代码,使用VerticalLayoutGroup和ContentSizeFitter组件的自动排序功能和Button的OnClick组件控制子物体的显示与隐藏来实现层级菜单的功能。
优缺点:
优点是不需要代码控制,简单易用
缺点是需要提前堆砌UI,工作量比较大,然后改动的时候耗费精力大
实现过程:
1、新建Scroll View
在这里插入图片描述
2、父节点
在这里插入图片描述
在这里插入图片描述
父节点有一个Button和一个隐藏的Image

Button

在这里插入图片描述
有两个功能
在这里插入图片描述
第一个就是显示跟自己位置坐标一样的子物体BtnSelecteStyle,因为BtnSelecteStyle是Button的子物体,所以BtnSelecteStyle就会挡住Button,为啥要挡住呢,因为还需要BtnSelecteStyle的OnClick将子节点收起来
BtnSelecteStyle的OnClick挂载的功能:
在这里插入图片描述
第二个就是显示子节点的容器也就是ImgBtnParentLayout

这个ImgBtnParentLayout就是子节点的容器

在这里插入图片描述
下面是几个子节点
在这里插入图片描述

OK。可以了

第四种实现效果

在这里插入图片描述

实现原理:这个是用代码动态生成的,其中一个脚本主要用来创建父物体和子物体,以及父级关系,另一个脚本是设置位置,箭头变化,按钮功能的初始化
优缺点:
优点是代码清晰,结构明了,可以实现层级多级显示、多级目录的设置、树级菜单等
缺点是没有判断最后一个节点的代码,最后一个节点无法设置图片,最后一个节点的功能没有添加
实现过程:
1、首先也是制作预制体
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
ArrowButton和ArrowButton2都是为了控制子节点的关闭和显示,不同的是ArrowButton是左边的小按钮,还有一个图片显示的功能,ArrowButton2是整体的按钮,不显示,但是点击整体都可以实现显示和隐藏子节点的功能

资源:

在这里述
在这里插入图片描述
在这里插入图片描述
图片是白的,仔细看一下还是能看到的 - -,然后保存下载,放到项目中去

2、编写脚本ItemPanelBase.cs

这个脚本是设置节点的位置,以及箭头切换的脚本

using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;public enum NameSort{
Default, Active, Passive}public class ItemPanelBase : MonoBehaviour{
private List
childList;//子物体集合 [HideInInspector] public Button downArrow;//下箭头按钮 public Button downArrow2;//下箭头按钮 public Sprite down, right, dot; public bool isOpen {
get; set; }//子物体开启状态 private Vector2 startSize;//起始大小 NameSort m_NameSore = NameSort.Default; string m_Name; private void Awake() {
childList = new List
(); downArrow = this.transform.Find("ContentPanel/ArrowButton").GetComponent

3、编写脚本PullDownList.cs

这个就是创建层级菜单的脚本:
比较繁琐

using System.Collections.Generic;using UnityEngine;public class PullDownList : MonoBehaviour{
private List
itemPanelList; public GameObject itemPanel; private void Awake() {
itemPanelList = new List
(); } void Start() {
for (int i = 0; i < 27; i++) {
//一级菜单 if(i == 0) {
GameObject newItemPanel = Instantiate(itemPanel); itemPanelList.Add(newItemPanel); newItemPanel.GetComponent
().SetBaseParent(this.transform); newItemPanel.GetComponent
().InitPanelContent("层级一"); } //二级菜单 if (i == 1) {
GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[0].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级二"); } else if (i == 2) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[0].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级二"); } //三级菜单 else if (i == 3) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[1].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级三"); } else if (i == 4) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[1].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级三"); } else if (i == 5) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[1].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级三"); } else if (i == 6) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[1].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级三"); } else if (i == 7) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[2].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级三"); } else if (i == 8) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[2].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级三"); } else if (i == 9) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[2].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级三"); } else if (i == 10) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[2].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级三"); } //四级菜单 else if (i == 11) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[3].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级四"); newItemPanel2.GetComponent
().SetName("层级四", NameSort.Active); } else if (i == 12) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[3].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级四"); newItemPanel2.GetComponent
().SetName("层级四", NameSort.Active); } else if (i == 13) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[4].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级四"); newItemPanel2.GetComponent
().SetName("层级四", NameSort.Active); } else if (i == 14) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[4].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级四"); newItemPanel2.GetComponent
().SetName("层级四", NameSort.Active); } else if (i == 15) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[5].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级四"); newItemPanel2.GetComponent
().SetName("层级四", NameSort.Active); } else if (i == 16) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[5].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级四"); newItemPanel2.GetComponent
().SetName("层级四", NameSort.Active); } else if (i == 17) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[6].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级四"); newItemPanel2.GetComponent
().SetName("层级四", NameSort.Active); } else if (i == 18) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[6].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级四"); newItemPanel2.GetComponent
().SetName("层级四", NameSort.Active); } else if (i == 19) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[7].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级四"); newItemPanel2.GetComponent
().SetName("层级四", NameSort.Passive); } else if (i == 20) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[7].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级四"); newItemPanel2.GetComponent
().SetName("层级四", NameSort.Passive); } else if (i == 21) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[8].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级四"); newItemPanel2.GetComponent
().SetName("层级四", NameSort.Passive); } else if (i == 22) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[8].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级四"); newItemPanel2.GetComponent
().SetName("层级四", NameSort.Passive); } else if (i == 23) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[9].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级四"); newItemPanel2.GetComponent
().SetName("层级四", NameSort.Passive); } else if (i == 24) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[9].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级四"); newItemPanel2.GetComponent
().SetName("层级四", NameSort.Passive); } else if (i == 25) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[10].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级四"); newItemPanel2.GetComponent
().SetName("层级四", NameSort.Passive); } else if (i == 26) { GameObject newItemPanel2 = Instantiate(itemPanel); itemPanelList.Add(newItemPanel2); newItemPanel2.GetComponent
().SetItemParent(itemPanelList[10].GetComponent
()); newItemPanel2.GetComponent
().InitPanelContent("层级四"); newItemPanel2.GetComponent
().SetName("层级四", NameSort.Passive); } } }}

将脚本挂载在Panel上面

在这里插入图片描述

OK,大功告成

第五种实现效果

在这里插入图片描述

实现原理:这个是用UI硬堆砌起来的层级菜单,然后通过代码控制对象的隐藏和显示,即可实现层级菜单的折叠与下拉功能,主要用到GridLayoutGroup组件来排序与更新
优缺点:
优点是操作简单,代码也简单,不需要太多的理解,然后可以显示多级菜单,多级内容,以及最后一个节点的功能与图片的设置功能
缺点是需要提前堆砌UI,可扩容性差,前期工作量大,然后后期修改工作量大,最重要的是我觉得这种实现方式蛮low的
实现过程:
1、显示制作UI
Panel上面挂载GridLayoutGroup组件
在这里插入图片描述
制作UI
在这里插入图片描述
在这里插入图片描述
UI的话就很简单,一个Button下面两个子物体一个text一个Image,text是显示内容,image是显示箭头

这时候就有人问了,那子物体怎么办,子物体也是同样的结构在这里插入图片描述

就是把image往后拉了一下

三级菜单也一样:

在这里插入图片描述
再加一个一级菜单:
在这里插入图片描述

是不是so easy…哈哈哈 真的好low

脚本功能就很简单

一级菜单控制它往下的所有子节点的隐藏于显示
在这里插入图片描述
二级菜单控制它往下的所有子节点的隐藏于显示
在这里插入图片描述

以此类推。。。。

2、编辑代码PullDown.cs

using UnityEngine;using UnityEngine.UI;public class PullDown : MonoBehaviour{
public Button m_Btn1;//一级菜单按钮 public Button m_Btn2;//二级菜单按钮 public Button m_Btn3;//三级菜单按钮 bool m_is1;//全局参数 控制开关 bool m_is2;//全局参数 控制开关 void Start() {
m_is1 = true; m_is2 = true; m_Btn1.onClick.AddListener(Btn1_Event); m_Btn2.onClick.AddListener(Btn2_Event); } public void Btn1_Event() {
if (m_is1) {
m_Btn2.gameObject.SetActive(false); m_Btn3.gameObject.SetActive(false); m_is1 = false; } else {
m_Btn2.gameObject.SetActive(true); m_Btn3.gameObject.SetActive(true); m_is1 = true; } } public void Btn2_Event() {
if (m_is2) {
m_Btn3.gameObject.SetActive(false); m_is2 = false; } else {
m_Btn3.gameObject.SetActive(true); m_is1 = true; } }}

OK了,快去试试吧

转载地址:https://itmonon.blog.csdn.net/article/details/100161230 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:【Unity3D开发小游戏】《宝石迷阵游戏》Unity开发教程
下一篇:【Unity3D】UGUI 文字实现进度等待、进度加载、进程等待演示动画

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年04月22日 01时05分25秒