Unity3D-UGUI应用篇使用UGUI实现层级菜单
Posted 恬静的小魔龙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity3D-UGUI应用篇使用UGUI实现层级菜单相关的知识,希望对你有一定的参考价值。
推荐阅读
大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。
一、前言
前段时间分享了UGUI的每个组件的属性和使用方法,比如Text、Button、Image、Toggle、InputField、ScrollView等等。
接着分享了UGUI的一些原理,比如说UGUI的渲染模式、UGUI的缩放计算、UGUI的描点定位、UGUI的自动布局等等。
相信大家看完后会对UGUI有一个比较全面的认识了。
下面,就继续分享UGUI的UI组件进行应用的实例。
这是本系列文章的第三篇:
【Unity3D-UGUI应用篇】(一)使用Text实现进度等待动画
【Unity3D-UGUI应用篇】(二)使用Image实现进度条动画
【Unity3D-UGUI应用篇】(三)使用UGUI实现层级菜单
【Unity3D-UGUI应用篇】(四)使用UGUI弹窗显示模型及弹窗模型交互
【Unity3D-UGUI应用篇】(五)使用Button完成鼠标移动到UI上面显示文字功能
【Unity3D-UGUI应用篇】(六)屏幕自适应(多分配率适配)
【Unity3D-UGUI应用篇】(七)UGUI实现窗口的自由拖拽
【Unity3D-UGUI应用篇】(八)Image实现画线、画三角形、画正方形、画圆
二、介绍及效果图
层级菜单在Unity中用到的并不多,主要是做分类的时候用的比较多,今天就给大家分享几个层级代码,扩充一下,写成插件也是不错的。
首先看一下效果吧。
第一种效果:
第二种效果:
第三种效果:
第四种效果:
第五种效果:
源文件:
Github下载地址:
LayerMenu.unitypackage
三、实现
第一种实现效果
实现原理:
这个是用系统自带的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<Button>().onClick.AddListener(OnButtonClick);
}
void OnButtonClick()
{
if (!isCanClick) return;
if (!isOpening)
StartCoroutine(ShowChildMenu());
else
StartCoroutine(HideChildMenu());
}
IEnumerator ShowChildMenu()
{
childMenu.gameObject.SetActive(true);
for (int i = 0; i < count; i++)
{
childs[i].localPosition -= i * offset;
yield return new WaitForSeconds(0.1f);
}
isCanClick = true;
isOpening = true;
}
IEnumerator HideChildMenu()
{
for (int i = count - 1; i >= 0; i--)
{
childs[i].localPosition += i * offset;
yield return new WaitForSeconds(0.1f);
}
childMenu.gameObject.SetActive(false);
isCanClick = true;
isOpening = false;
}
}
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<RectTransform>();
//获取到menuinfo里面的信息 3 3 4 4 5 5
textAsset = Resources.Load<TextAsset>("menuInfo");
//获取到父物体 设置父物体的高度
parentRect = Resources.Load<RectTransform>("parentMenu");
parentOffset = new Vector3(0, parentRect.rect.height);
//获取到子物体 设置子物体的高度
childRect = Resources.Load<RectTransform>("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<ParentMenu>().Init(childRect, cntArr[i]);
int j = i;
//父物体上面的button绑定事件
parentArr[i].GetComponent<Button>().onClick.AddListener(() => { OnButtonClick(j); });
}
}
void OnButtonClick(int i)
{
//如果iscanclick为false则return 因为已经点击过了 不能再点击了 除非升起来的时候将isCanClick改为true
if (!parentArr[i].GetComponent<ParentMenu>().isCanClick)
return;
parentArr[i].GetComponent<ParentMenu>().isCanClick = false;
//isopening 为true 执行 menuup 为flase执行menuDown
if (!parentArr[i].GetComponent<ParentMenu>().isOpening)
StartCoroutine(MenuDown(i));
else
StartCoroutine(MenuUp(i));
}
IEnumerator MenuDown(int index)
{
for (int i = 0; i < cntArr[index]; i++)
{
//更新content高度
content.sizeDelta = new Vector2(content.rect.width,
content.rect.height + childOffset.y);
for (int j = index + 1; j < parentArr.Length; j++)
{
parentArr[j].localPosition -= childOffset;
}
yield return new WaitForSeconds(0.1f);
}
}
IEnumerator MenuUp(int index)
{
for (int i = 0; i < cntArr[index]; i++)
{
//更新content高度
content.sizeDelta = new Vector2(content.rect.width,
content.rect.height - childOffset.y);
for (int j = index + 1; j < parentArr.Length; j++)
{
parentArr[j].localPosition += childOffset;
}
yield return new WaitForSeconds(0.1f);
}
}
}
将这个脚本挂载到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<Transform> children = new List<Transform>();
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<Transform>("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<Transform>("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<Options_Triangle>().triangle.transform.eulerAngles = new Vector3(0, 0, -90);
PublicData.parent.GetComponent<Options_Triangle>().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<Options_Triangle>().triangle.transform.eulerAngles = new Vector3(0, 0, -90);
Transform content = Instantiate(Resources.Load<Transform>("Options"));
content.transform.SetParent(PublicData.parent, false);
content.transform.position = new Vector3(PublicData.currentPosition.x + 16, PublicData.currentPosition.y - 32, 0);
PublicData.parent.GetComponent以上是关于Unity3D-UGUI应用篇使用UGUI实现层级菜单的主要内容,如果未能解决你的问题,请参考以下文章
Unity3D-UGUI应用篇Image实现画线画三角形画正方形画圆