@Unity,UI制作

Unity3D——如何实时获取DropDown控件的状态(展开或关闭)

Unity的UGUI中仅有DropDown控件,但是没有常用的下拉菜单控件,得自己用DropDown做,自己做的话就要协调好各个DropDown控件。因为我们平时使用的菜单栏一旦点击了其中一个下拉菜单,下拉菜单展开,再将鼠标移动到另一个下拉菜单之上时,刚打开的下拉菜单会自动关闭,鼠标所悬浮于的其上的下拉菜单会自动打开。可是在Unity中,如果我们仅仅将几个DorpDown控件放在一起,而不协调它们之间的关系的话。那么,当我们点击DropDown_A,DropDown_A展开,再将鼠标悬浮于DropDown_B之上,DropDown_A不会关闭,DropDown_B也不会展开,必须要先点击以下鼠标,退出DropDown_A,再点击一下鼠标,打开DropDown_B,这很显然不是我们要的效果。所以,为了在Unity中实现真正的菜单栏效果,我们需要将多个DropDown控件配合使用,而配合使用的过程中,实时获取各个下拉菜单的状态,知道其是展开还是关闭是尤为重要的。当然了,光解决这一个问题不足以制作出真正的菜单栏,这里就介绍这一个问题,剩下的我以后再写到别的帖子里。

接下来我介绍两种方法,一种笨办法,不建议采用,但是我有一段时间一直找不到更好的办法,只能用这个笨办法,所以也记录下来。第二种方法我感觉还不错,推荐使用。

方法一

首先,DropDown控件本身没有一项属性表征其是否展开,所以我们不能直接从控件本身得到它的状态。但是,当我们打开下拉菜单时,在Hierarchy面板中我们可以发现在DropDown对象之下生成了一个名为DropDown List的子对象:

unity 根据路径查找某个子节点 unity dropdown 查找_下拉菜单


当我们关闭下拉菜单后,该子对象消失:

unity 根据路径查找某个子节点 unity dropdown 查找_ugui_02


利用这一点,我们有了一个能够表示下拉菜单是否展开的对象,利用它就有了我的笨办法。当我需要知道这个下拉菜单是否展开时,使用Find()方法寻找这个DropDown List.

if (GameObject.Find("MenuCanvas/FileDropList/Dropdown List"))

找到了自然下拉菜单是展开的,否则就是关闭的。不过众所周知,Find()能不用就尽量不用,虽然我在这里把路径写清楚了,Find()在遍历的时候效率会高一些,但如果是要实时获取下拉菜单的状态,需要在Update()或者FixedUpdate()中使用的话,那简直太难受了。下面介绍方法2就好多了。

方法二

所以后来经过在各种论坛查资料,我了解到, 我在方法一种所提到的这个Dropdown List对象是以下拉菜单对象下的子对象“Template”对象为模板动态创建的。 也就是说,每当我打开下拉菜单,都会以“Template”对象为模板创建一个Dropdown List对象,两者所附加的脚本以及各项设置均相同。于是乎,我想到如果在“Template”对象上添加一个脚本,在Start()中读取脚本所附加的对象名,判断是否为“DropDown List”,如果是的话,证明打开了下拉菜单:

void Start()
{
    if (this.name == "Dropdown List")
    {
        //FileListOpen是其他下拉菜单所附加的脚本中表示文件下拉菜单是否展开的一个布尔值
        //我在这里相当于告诉其他下拉菜单,文件下拉菜单已经展开
        OtherDropList.GetComponent<DropListController>().FileListOpen = true;
    }
}

当下拉菜单关闭时,DropDown List会被销毁,所以在OnDestroy()中修改其他下拉菜单上的脚本中表示文件下拉菜单是否展开的布尔值:

void OnDestroy()
{
    if (this.name == "Dropdown List")
    {        
         OtherDropList.GetComponent<DropListController>().FileListOpen = false;
    }
}

这种办法避免了使用Find(),也不用在Update()或者FixedUpdate()中执行,但是却可以实时的获取下拉菜单的状态。