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

不带动画
在这里插入图片描述
带动画
在这里插入图片描述
实现代码
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地址,扫下方码->历史消息->找到当前文章末尾即可获取

更多内容,欢迎访问:


在这里插入图片描述

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值