ImageVerifierCode 换一换
格式:DOCX , 页数:15 ,大小:281.29KB ,
资源ID:6239039      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6239039.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Unity UGUI自定义树形菜单TreeView.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Unity UGUI自定义树形菜单TreeView.docx

1、Unity UGUI自定义树形菜单TreeViewUnity UGUI自定义树形菜单(TreeView)如果你需要的也是这种效果,那你就来对地方了!目前,我们这个树形菜单展现出来的功能如下:1、可以动态配置数据源;2、点击每个元素的上下文菜单按钮(也就是图中的三角形按钮),可以收缩或展开它的子元素;3、可以单独判断某一元素的复选框是否被勾选,或者直接获取当前树形菜单中所有被勾选的元素;4、树形菜单统一控制其下所有子元素按钮的事件分发;5、可自动调节的滚动视野边缘,根据当前可见的子元素数量进行横向以及纵向的伸缩;一、 首先,我们先制作子元素的模板(Template),也就是图中菜单的单个元素,用

2、它来根据数据源动态克隆出多个子元素,这里的话,很显然我们的模板是由两个Button加一个Toggle和一个Text组成的,如下:二、我们的每个子元素都会携带一个TreeViewItem脚本,用于描述自身在整个树形菜单中与其他元素的父子关系,而整个树形菜单的控制由TreeViewControl来实现,首先,TreeViewControl会根据提供的数据源来生成所有的子元素,当然,改变数据源之后进行重新生成的时候也是这个方法,干的事情很简单,就是用模板不停的创建元素,并给他们建立父子关系:csharp view plain copy/ / 生成树形菜单 / public void Generate

3、TreeView() /删除可能已经存在的树形菜单元素 if (_treeViewItems != null) for (int i = 0; i _treeViewItems.Count; i+) Destroy(_treeViewItemsi); _treeViewItems.Clear(); /重新创建树形菜单元素 _treeViewItems = new List(); for (int i = 0; i Data.Count; i+) GameObject item = Instantiate(Template); if (Datai.ParentID = -1) item.GetC

4、omponent().SetHierarchy(0); item.GetComponent().SetParent(null); else TreeViewItem tvi = _treeViewItemsDatai.ParentID.GetComponent(); item.GetComponent().SetHierarchy(tvi.GetHierarchy() + 1); item.GetComponent().SetParent(tvi); tvi.AddChildren(item.GetComponent(); item.transform.name = TreeViewItem;

5、 item.transform.FindChild(TreeViewText).GetComponent().text = Datai.Name; item.transform.SetParent(TreeItems); item.transform.localPosition = Vector3.zero; item.transform.localScale = Vector3.one; item.transform.localRotation = Quaternion.Euler(Vector3.zero); item.SetActive(true); _treeViewItems.Add

6、(item); 三、树形菜单生成完毕之后此时所有元素虽然都记录了自身与其他元素的父子关系,但他们的位置都是在Vector3.zero的,毕竟我们的菜单元素在创建的时候都是一股脑儿的丢到原点位置的,创建君可不管这么多元素挤在一堆会不会憋死,好吧,之后规整列队的事情就交给刷新君来完成了,刷新君玩的一手好递归,它会遍历所有元素并剔除不可见的元素(也就是点击三角按钮隐藏了),并将它们一个一个的重新排列整齐,子排在父之后,孙排在子之后,以此类推.它会遍历每个元素的子元素列表,发现子元素可见便进入子元素列表,发现孙元素可见便进入孙元素列表:csharp view plain copy/ / 刷新树形菜单

7、/ public void RefreshTreeView() _yIndex = 0; _hierarchy = 0; /复制一份菜单 _treeViewItemsClone = new List(_treeViewItems); /用复制的菜单进行刷新计算 for (int i = 0; i _treeViewItemsClone.Count; i+) /已经计算过或者不需要计算位置的元素 if (_treeViewItemsClonei = null | !_treeViewItemsClonei.activeSelf) continue; TreeViewItem tvi = _tre

8、eViewItemsClonei.GetComponent(); _treeViewItemsClonei.GetComponent().localPosition = new Vector3(tvi.GetHierarchy() * HorizontalItemSpace, _yIndex,0); _yIndex += (-(ItemHeight + VerticalItemSpace); if (tvi.GetHierarchy() _hierarchy) _hierarchy = tvi.GetHierarchy(); /如果子元素是展开的,继续向下刷新 if (tvi.IsExpand

9、ing) RefreshTreeViewChild(tvi); _treeViewItemsClonei = null; /重新计算滚动视野的区域 float x = _hierarchy * HorizontalItemSpace + ItemWidth; float y = Mathf.Abs(_yIndex); transform.GetComponent().content.sizeDelta = new Vector2(x, y); /清空复制的菜单 _treeViewItemsClone.Clear(); / / 刷新元素的所有子元素 / void RefreshTreeViewC

10、hild(TreeViewItem tvi) for (int i = 0; i tvi.GetChildrenNumber(); i+) tvi.GetChildrenByIndex(i).gameObject.GetComponent().localPosition = new Vector3(tvi.GetChildrenByIndex(i).GetHierarchy() * HorizontalItemSpace, _yIndex, 0); _yIndex += (-(ItemHeight + VerticalItemSpace); if (tvi.GetChildrenByIndex

11、(i).GetHierarchy() _hierarchy) _hierarchy = tvi.GetChildrenByIndex(i).GetHierarchy(); /如果子元素是展开的,继续向下刷新 if (tvi.GetChildrenByIndex(i).IsExpanding) RefreshTreeViewChild(tvi.GetChildrenByIndex(i); int index = _treeViewItemsClone.IndexOf(tvi.GetChildrenByIndex(i).gameObject); if (index = 0) _treeViewIt

12、emsCloneindex = null; 我这里将所有的元素复制了一份用于计算位置,主要就是为了防止在进行一轮刷新时某个元素被访问两次或以上,因为刷新的时候会遍历所有可见元素,如果第一次访问了元素A(元素A的位置被刷新),根据元素A的子元素列表访问到了元素B(元素B的位置被刷新),一直到达子元素的底部后,当不存在更深层次的子元素时,那么返回到元素A之后的元素继续访问,这时在所有元素列表中元素B可能在元素A之后,也就是说元素B已经通过父元素访问过了,不需要做再次访问,他的位置已经是最新的了,而之后根据列表索引很可能再次访问到元素B,如果是这样的话元素B的位置又要被刷新一次,甚至多次,性能影响不

13、说,第二次计算的位置已经不是正确的位置了。四、菜单已经创建完毕并且经过了一轮刷新,此时它展示出来的就是这样一个所有子元素都展开的形状(我在demo中指定了数据源,关于数据源怎么设置在后面):我们要在每个元素都携带的脚本TreeViewItem中对自身的那个三角形的上下文按钮监听,当鼠标点击它时它的子元素就会被折叠或者展开:csharp view plain copy/ / 点击上下文菜单按钮,元素的子元素改变显示状态 / void ContextButtonClick() if (IsExpanding) transform.FindChild(ContextButton).GetCompon

14、ent().localRotation = Quaternion.Euler(0, 0, 90); IsExpanding = false; ChangeChildren(this, false); else transform.FindChild(ContextButton).GetComponent().localRotation = Quaternion.Euler(0, 0, 0); IsExpanding = true; ChangeChildren(this, true); /刷新树形菜单 Controler.RefreshTreeView(); / / 改变某一元素所有子元素的显

15、示状态 / void ChangeChildren(TreeViewItem tvi, bool value) for (int i = 0; i tvi.GetChildrenNumber(); i+) tvi.GetChildrenByIndex(i).gameObject.SetActive(value); ChangeChildren(tvi.GetChildrenByIndex(i), value); IsExpanding做为每个元素的字段用于设置或读取自身子元素的显示状态,这里根据改变的状态会递归循环此元素的所有子元素及孙元素,让他们可见或隐藏。五、对所有的子元素进行统一的事件分

16、发,这里主要就有鼠标点击这一个事件:每个元素都会注册这个事件:(TreeViewItem.cs)csharp view plain copyvoid Awake() /上下文按钮点击回调 transform.FindChild(ContextButton).GetComponent().onClick.AddListener(ContextButtonClick); transform.FindChild(TreeViewButton).GetComponent().onClick.AddListener(delegate () Controler.ClickItem(gameObject);

17、 ); 树形菜单控制器统一分发:(TreeViewControl.cs)csharp w plain copypublic delegate void ClickItemdelegate(GameObject item); public event ClickItemdelegate ClickItemEvent; / / 鼠标点击子元素事件 / public void ClickItem(GameObject item) ClickItemEvent(item); 六、获取元素的复选框状态判断是否被勾选:根据元素名称进行筛选,获取此元素的选中状态,如果存在同名元素的话这个可能不好使:csha

18、rp view plain copy/ / 返回指定名称的子元素是否被勾选 / public bool ItemIsCheck(string itemName) for (int i = 0; i _treeViewItems.Count; i+) if (_treeViewItemsi.transform.FindChild(TreeViewText).GetComponent().text = itemName) return _treeViewItemsi.transform.FindChild(TreeViewToggle).GetComponent().isOn; return fa

19、lse; 返回树形菜单中所有被勾选的子元素名称集合:csharp view plain copy/ / 返回树形菜单中被勾选的所有子元素名称 / public List ItemsIsCheck() List items = new List(); for (int i = 0; i _treeViewItems.Count; i+) if (_treeViewItemsi.transform.FindChild(TreeViewToggle).GetComponent().isOn) items.Add(_treeViewItemsi.transform.FindChild(TreeView

20、Text).GetComponent().text); return items; 七、接下来是我们的数据格式TreeViewData,树形菜单的数据源是由这个格式组成的集合:csharp view plain copy/ / 当前树形菜单的数据源 / HideInInspector public List Data = null; 每一个TreeViewData代表一个元素,Name为显示的文本内容,ParentID为它指向的父元素在整个数据集合中的索引,从0开始,-1代表不存在父元素的根元素,当然有时候数据源并不是这个样子的,可能是XML,可能是json,不过都可以通过解析数据源之后再变换

21、成这种方式:csharp view plain copy/ / 树形菜单数据 / public class TreeViewData / / 数据内容 / public string Name; / / 数据所属的父ID / public int ParentID; 八、属性面板的参数:Template:当前树形菜单的元素模板;TreeItems:当前树形菜单的元素根物体,自动指定的,这个别去动;VerticalItemSpace:相邻元素之间的纵向间距;HorizontalItemSpace:不同层级元素之间的横向间距;ItemWidth:元素的宽度,若自行修改过Template,这里的值需

22、要自己去计算Template的大概宽度;ItemHeight:元素的高度,若自行修改过Template,这里的值需要自己去计算Template的大概高度;九、我已经将TreeView打包成了一个插件,在Unity中导入他,便可以直接使用TreeView:导入TreeView.unitypackage以后,先在场景中创建一个Canvas(画布),然后右键直接创建TreeView:之后在其他脚本中拿到这个TreeView,直接为他指定数据源(我这里是手动生成,篇幅有点长):csharp view plain copy/生成数据 List datas = new List(); TreeViewDa

23、ta data = new TreeViewData(); data.Name = 第一章; data.ParentID = -1; datas.Add(data); data = new TreeViewData(); data.Name = 1.第一节; data.ParentID = 0; datas.Add(data); data = new TreeViewData(); data.Name = 1.第二节; data.ParentID = 0; datas.Add(data); data = new TreeViewData(); data.Name = 1.1.第一课; data

24、.ParentID = 1; datas.Add(data); data = new TreeViewData(); data.Name = 1.2.第一课; data.ParentID = 2; datas.Add(data); data = new TreeViewData(); data.Name = 1.1.第二课; data.ParentID = 1; datas.Add(data); data = new TreeViewData(); data.Name = 1.1.1.第一篇; data.ParentID = 3; datas.Add(data); data = new Tre

25、eViewData(); data.Name = 1.1.1.第二篇; data.ParentID = 3; datas.Add(data); data = new TreeViewData(); data.Name = 1.1.1.2.第一段; data.ParentID = 7; datas.Add(data); data = new TreeViewData(); data.Name = 1.1.1.2.第二段; data.ParentID = 7; datas.Add(data); data = new TreeViewData(); data.Name = 1.1.1.2.1.第一题

26、; data.ParentID = 8; datas.Add(data); /指定数据源 TreeView.Data = datas; 然后生成树形菜单,连带刷新一次:csharp view plain copy/重新生成树形菜单 TreeView.GenerateTreeView(); /刷新树形菜单 TreeView.RefreshTreeView(); 然后注册子元素的鼠标点击事件(委托类型为返回值void,带一个Gameobject类型参数,参数item为被鼠标点中的那个元素的gameobject):csharp view ain copy/注册子元素的鼠标点击事件 TreeView.ClickItemEvent += CallBack; void CallBack(GameObject item) Debug.Log(点击了 + item.transform.FindChild(TreeViewText).GetComponent().text); 以及要获取某一元素的勾选状态:csharp view plain copybool isCheck = TreeView.ItemIsCheck(第一章); Debug.Log(当前树形菜单中的元素 第一章 + (isCheck?已被选中!:未被选中!); 和获取所有

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1