Unity 中实现一个简单的可折叠菜单

mac2025-06-06  59

不带动画

带动画

实现代码

public class Nodes : BaseNode { /// <summary> /// 只在内存中分配一次 /// </summary> private static Text text; public override void Start() { text = GameObject.Find("Canvas/CurrentClickNodeText").GetComponent<Text>(); base.Start(); GetComponent<Button>().onClick.AddListener(() => { SwitchNode(); Text txt = transform.GetChild(0).GetComponent<Text>(); text.text = txt.text; }); } } public abstract class BaseNode : MonoBehaviour { /// <summary> /// 当前节点组的父容器 /// </summary> public RectTransform parentRectTransform; /// <summary> /// 如果当前节点存在子节点 /// </summary> public List<BaseNode> childNodes; /// <summary> /// 上一个被选中的节点是哪一个 /// </summary> public static BaseNode CurrentNode { get; private set; } /// <summary> /// 当前节点是否被打开 /// </summary> private bool isOpen = false; /// <summary> /// 计算要容器的目标大小 /// </summary> private float EndContainerWidth; /// <summary> /// 计算容器的初始大小 /// </summary> private float StartContainerWidth; /// <summary> /// 弹力速度,改变可更改弹性速度,可自己手动更改 /// </summary> [Range(0.0f, 1f)] private float EleasticSpeed = 0.5f; public virtual void Start() { if (parentRectTransform != null) { StartContainerWidth = parentRectTransform.rect.width; if (this.childNodes != null && this.childNodes.Count != 0) { float space = parentRectTransform.GetComponent<HorizontalLayoutGroup>().spacing; for (int i = 0; i < this.childNodes.Count; i++) { EndContainerWidth += childNodes[i].GetComponent<RectTransform>().rect.width + space; } EndContainerWidth += this.parentRectTransform.rect.width; } } } /// <summary> /// 点击按钮时,切换节点的开关,以及改变父容器的大小 /// </summary> public void SwitchNode() { if (CurrentNode != null && CurrentNode.childNodes.Count != 0) { //如果点击的是节点本身 if (CurrentNode == this && CurrentNode.childNodes != null) { this.isOpen = !isOpen; StartCoroutine(CotainerSiwtch(isOpen, CurrentNode)); foreach (var node in CurrentNode.childNodes) { //关闭上一个被打开的Node //node.gameObject.SetActive(isOpen); node.isOpen = false; } CurrentNode = null; return; } else { if (this.childNodes.Count == 0) return; StartCoroutine(CotainerSiwtch(false, CurrentNode)); foreach (var node in CurrentNode.childNodes) { //关闭当前节点的所有子节点 //node.gameObject.SetActive(false); node.isOpen = false; } CurrentNode.isOpen = false; CurrentNode = null; } } if (this.childNodes != null && this.childNodes.Count != 0) { this.isOpen = !isOpen; StartCoroutine(CotainerSiwtch(this.isOpen, this)); foreach (var node in this.childNodes) { //需要启用当前对象 //node.gameObject.SetActive(this.isOpen); node.isOpen = this.isOpen; } CurrentNode = this; CurrentNode.childNodes = this.childNodes; } } /// <summary> ///容器开关,控制容器的打开关闭 /// </summary> /// <param name="open"></param> /// <returns></returns> private IEnumerator CotainerSiwtch(bool open, BaseNode nodes) { if (this.parentRectTransform != null) { float t = 0; float targetValue = open ? EndContainerWidth : StartContainerWidth; while (t < EleasticSpeed) { yield return null; float value = Mathf.Lerp(nodes.parentRectTransform.sizeDelta.x, targetValue, t / EleasticSpeed); t += Time.deltaTime; nodes.parentRectTransform.sizeDelta = new Vector2(value, nodes.parentRectTransform.sizeDelta.y); } } }

Demo地址,扫下方码->历史消息->找到当前文章末尾即可获取

更多内容,欢迎访问:

最新回复(0)