using System.Collections; using System.Collections.Generic; using UnityEngine; using System.IO; using System.Runtime.Serialization.Formatters.Binary; namespace SuperTreeView { public class DemoScene2Script : MonoBehaviour { public TreeView mTreeView; int mCurSelectedItemId = 0; int mNewItemCount = 0; void Start() { SpriteResMgr rm = SpriteResMgr.Instance; mTreeView.OnTreeListAddOneItem = OnTreeListAddOneItem; //mTreeView.OnTreeListDeleteOneItem = OnTreeListDeleteOneItem; mTreeView.OnItemExpandBegin = OnItemExpandBegin; mTreeView.OnItemCollapseBegin = OnItemCollapseBegin; mTreeView.OnItemCustomEvent = OnItemCustomEvent; mTreeView.OnTreeListRepositionFinish = OnTreeListRepositionFinish; mTreeView.InitView(); BuildTreeAutomatically(); } void BuildTreeAutomatically() { var datas = new List { // --- 胸部体表标志 --- new[] { "胸部体表标志", "胸骨柄", "XiongGuBing" }, new[] { "胸部体表标志", "胸骨上切迹", "XiongGuShangQieJi" }, new[] { "胸部体表标志", "胸骨角", "XiongGuJiao" }, new[] { "胸部体表标志", "剑突", "JianTu" }, new[] { "胸部体表标志", "1-7肋骨", "LeiGu1-7" }, new[] { "胸部体表标志", "11-12肋骨", "LeiGu11-12" }, new[] { "胸部体表标志", "肋间隙", "LeiJianXi" }, new[] { "胸部体表标志", "肩胛骨", "JianJiaGu" }, new[] { "胸部体表标志", "肩胛下角", "JianJiaXiaJiao" }, // --- 垂直线标志 --- new[] { "垂直线标志", "前正中线", "QianZhengZhongXian" }, new[] { "垂直线标志", "(左、右)锁骨中线", "SuoGuZhongXian" }, new[] { "垂直线标志", "(左、右)胸骨线", "XiongGuXian" }, new[] { "垂直线标志", "(左、右)胸骨旁线", "XiongGuPangXian" }, new[] { "垂直线标志", "(左、右)腋前线", "YeQianXian" }, new[] { "垂直线标志", "(左、右)腋后线", "YeHouXian" }, new[] { "垂直线标志", "(左、右)腋中线", "YeZhongXian" }, new[] { "垂直线标志", "(左、右)肩胛线", "JianJiaXian" }, new[] { "垂直线标志", "后正中线", "HouZhengZhongXian" }, // --- 解剖区域 --- new[] { "解剖区域", "(左、右)肩胛上区", "JianJiaShangQu" }, new[] { "解剖区域", "(左、右)肩胛下区", "JianJiaXiaQu" }, new[] { "解剖区域", "(左、右)肩胛间区", "JianJiaQuJian" }, // --- 动画 --- new[] { "肺功能动画", "FeiGongNengDongHua" }, new[] { "心功能动画", "XinGongNengDongHua" }, // --- 肺部听诊 --- new[] { "肺部听诊", "正常呼吸音", "气管呼吸音", "QiGuanHuXiYin" }, new[] { "肺部听诊", "正常呼吸音", "支气管呼吸音", "ZhiQiGuanHuXiYin" }, new[] { "肺部听诊", "正常呼吸音", "支气管肺泡呼吸音", "ZhiQiGuanFeiPaoHuXiYin" }, new[] { "肺部听诊", "正常呼吸音", "肺泡呼吸音", "FeiPaoHuXiYin" }, new[] { "肺部听诊", "异常呼吸音", "异常肺泡呼吸音", "肺泡呼吸音减弱或消失", "FeiPaoHuXiYinJianRuoHuoXiaoShi" }, new[] { "肺部听诊", "异常呼吸音", "异常肺泡呼吸音", "肺泡呼吸音增强", "FeiPaoHuXiYinZengQiang" }, new[] { "肺部听诊", "异常呼吸音", "异常肺泡呼吸音", "呼吸音延长", "HuXiYinYanChang" }, new[] { "肺部听诊", "异常呼吸音", "异常肺泡呼吸音", "断续性呼吸音", "DuanXuXingHuXiYin" }, new[] { "肺部听诊", "异常呼吸音", "异常肺泡呼吸音", "粗糙性呼吸音", "CuCaoXingHuXiYin" }, new[] { "肺部听诊", "异常呼吸音", "异常支气管呼吸音", "YiChangZhiQiGuanHuXiYin" }, new[] { "肺部听诊", "异常呼吸音", "异常支气管肺泡呼吸音", "YiChangZhiQiGuanFeiPaoHuXiYin" }, new[] { "肺部听诊", "异常呼吸音", "啰音", "粗湿啰音(大水泡音)", "CuShiLuoYin" }, new[] { "肺部听诊", "异常呼吸音", "啰音", "中湿啰音(中水泡音)", "ZhongShiLuoYin" }, new[] { "肺部听诊", "异常呼吸音", "啰音", "细湿啰音(小水泡音)", "XiShiLuoYin" }, new[] { "肺部听诊", "异常呼吸音", "啰音", "Velcro啰音", "VelcroLuoYin" }, new[] { "肺部听诊", "异常呼吸音", "啰音", "捻发音", "NianFaYin" }, new[] { "肺部听诊", "异常呼吸音", "啰音", "高调干啰音(哨笛音)", "GaoDiaoGanLuoYin" }, new[] { "肺部听诊", "异常呼吸音", "啰音", "低调干啰音(鼾音)", "DiDiaoGanLuoYin" }, new[] { "肺部听诊", "异常呼吸音", "胸膜摩擦音", "XiongMoMoCaYin" }, // --- 心脏听诊 --- new[] { "心脏听诊", "心脏瓣膜听诊区", "二尖瓣区(心尖区)", "ErJianBanQu" }, new[] { "心脏听诊", "心脏瓣膜听诊区", "肺动脉瓣区", "FeiDongMaiBanQu" }, new[] { "心脏听诊", "心脏瓣膜听诊区", "主动脉瓣区", "ZhuDongMaiBanQu" }, new[] { "心脏听诊", "心脏瓣膜听诊区", "主动脉瓣第二听诊区", "ZhuDongMaiBanDiErTingZhenQu" }, new[] { "心脏听诊", "心脏瓣膜听诊区", "三尖瓣区", "SanJianBanQu" }, new[] { "心脏听诊", "心率", "XinLv" }, new[] { "心脏听诊", "心音", "第一心音", "DiYiXinYin" }, new[] { "心脏听诊", "心音", "第二心音", "DiErXinYin" }, new[] { "心脏听诊", "心音", "第三心音", "DiSanXinYin" }, new[] { "心脏听诊", "心音", "第四心音", "DiSiXinYin" }, new[] { "心脏听诊", "心音", "第一心音增强", "DiYiXinYinZengQiang" }, new[] { "心脏听诊", "心音", "第一心音减弱", "DiYiXinYinJianRuo" }, new[] { "心脏听诊", "心音", "第一心音强弱不等", "DiYiXinYinQiangRuoBuDeng" }, new[] { "心脏听诊", "心音", "第二心音增强", "DiErXinYinZengQiang" }, new[] { "心脏听诊", "心音", "第二心音减弱", "DiErXinYinJianRuo" }, new[] { "心脏听诊", "心音", "第一心音分裂", "DiYiXinYinFenLie" }, new[] { "心脏听诊", "心音", "第二心音通常分裂", "DiErXinYinTongChangFenLie" }, new[] { "心脏听诊", "心音", "第二心音固定分裂", "DiErXinYinGuDingFenLie" }, new[] { "心脏听诊", "心音", "第二心音反常分裂", "DiErXinYinFanChangFenLie" }, new[] { "心脏听诊", "额外心音", "舒张期额外心音", "舒张早期奔马律", "ShuZhangZaoQiBenMaLv" }, new[] { "心脏听诊", "额外心音", "舒张期额外心音", "舒张晚期奔马律", "ShuZhangWanQiBenMaLv" }, new[] { "心脏听诊", "额外心音", "舒张期额外心音", "开瓣音", "KaiBanYin" }, new[] { "心脏听诊", "额外心音", "收缩期额外心音", "收缩中、晚期喀喇音", "ShouSuoZhongWanQiKaLaYin" }, new[] { "心脏听诊", "心脏杂音", "收缩期杂音", "二尖瓣区", "ErJianBanQu2" }, new[] { "心脏听诊", "心脏杂音", "收缩期杂音", "主动脉瓣区", "ZhuDongMaiBanQu2" }, new[] { "心脏听诊", "心脏杂音", "收缩期杂音", "肺动脉瓣区", "FeiDongMaiBanQu2" }, new[] { "心脏听诊", "心脏杂音", "收缩期杂音", "三尖瓣区", "SanJianBanQu2" }, new[] { "心脏听诊", "心脏杂音", "舒张期杂音", "二尖瓣区", "ErJianBanQu3" }, new[] { "心脏听诊", "心脏杂音", "舒张期杂音", "主动脉瓣区", "ZhuDongMaiBanQu3" }, new[] { "心脏听诊", "心脏杂音", "舒张期杂音", "肺动脉瓣区", "FeiDongMaiBanQu3" }, new[] { "心脏听诊", "心脏杂音", "舒张期杂音", "三尖瓣区", "SanJianBanQu3" }, new[] { "心脏听诊", "心脏杂音", "连续性杂音", "LianXuXingZaYin" }, new[] { "心脏听诊", "心脏杂音", "心包摩擦音", "XinBaoMoCaYin" } }; // 【修复点】创建一个虚拟的根节点对象,作为字典的 Key,避免使用 null TreeViewItem virtualRoot = new TreeViewItem(); // 缓存结构:Key=父节点对象, Value=该父节点下的子节点字典 (名称->节点对象) var nodeCache = new Dictionary>(); // 初始化:将虚拟根节点的子节点字典放入缓存 nodeCache[virtualRoot] = new Dictionary(); foreach (var row in datas) { if (row.Length == 0) continue; // 初始父节点设为虚拟根节点 TreeViewItem currentParent = virtualRoot; // 计算需要生成的节点数量 (总长度 - 1,因为最后一个是数据 Payload) int nodeCount = row.Length - 1; for (int i = 0; i < nodeCount; i++) { string nodeName = row[i]; // 判断当前节点是否携带数据:只有当它是这一行的最后一个生成节点时,才携带数据 bool isLastNodeInRow = (i == nodeCount - 1); string payload = isLastNodeInRow ? row[row.Length - 1] : null; // 确保当前父节点在缓存中有对应的子节点字典 if (!nodeCache.ContainsKey(currentParent)) { nodeCache[currentParent] = new Dictionary(); } var childrenMap = nodeCache[currentParent]; TreeViewItem newNode; // 1. 检查是否已存在同名子节点 if (childrenMap.TryGetValue(nodeName, out newNode)) { // 节点已存在,直接复用 } else { // 2. 创建新节点 if (currentParent == virtualRoot) { // 如果是虚拟根的直连子节点,直接添加到 mTreeView newNode = mTreeView.AppendItem("ItemPrefab1"); } else { // 否则添加到父节点的 ChildTree newNode = currentParent.ChildTree.AppendItem("ItemPrefab1"); } // 3. 设置信息 var script = newNode.GetComponent(); if (script != null) { if (!string.IsNullOrEmpty(payload)) { // 有数据:SetItemInfo("", "名称", "数据") script.SetItemInfo("", nodeName, payload); } else { // 无数据:SetItemInfo("", "名称") script.SetItemInfo("", nodeName); } } // 4. 加入缓存,方便后续行复用 childrenMap[nodeName] = newNode; // 为新节点初始化一个空的子节点字典(预防未来可能有更深层级) nodeCache[newNode] = new Dictionary(); } // 5. 更新父节点,进入下一层循环 currentParent = newNode; } } Debug.Log("TreeView 构建完成!共处理 " + datas.Count + " 条数据。"); } void OnItemExpandBegin(TreeViewItem item) { ItemScript2 st = item.GetComponent(); st.SetExpandStatus(true); } void OnItemCollapseBegin(TreeViewItem item) { ItemScript2 st = item.GetComponent(); st.SetExpandStatus(false); } void OnItemCustomEvent(TreeViewItem item, CustomEvent customEvent, System.Object param) { if (customEvent == CustomEvent.ItemClicked) { ItemScript2 st = item.GetComponent(); if (mCurSelectedItemId > 0) { if (item.ItemId == mCurSelectedItemId) { return; } TreeViewItem curSelectedItem = mTreeView.GetTreeItemById(mCurSelectedItemId); if (curSelectedItem != null) { curSelectedItem.GetComponent().IsSelected = false; } mCurSelectedItemId = 0; } st.IsSelected = true; mCurSelectedItemId = item.ItemId; Debug.Log((string)param); } } void OnTreeListAddOneItem(TreeList treeList) { int count = treeList.ItemCount; TreeViewItem parentTreeItem = treeList.ParentTreeItem; if (count > 0 && parentTreeItem != null) { ItemScript2 st = parentTreeItem.GetComponent(); st.SetExpandBtnVisible(true); st.SetExpandStatus(parentTreeItem.IsExpand); } } TreeViewItem CurSelectedItem { get { if (mCurSelectedItemId <= 0) { return null; } TreeViewItem item = mTreeView.GetTreeItemById(mCurSelectedItemId); if (item == null) { mCurSelectedItemId = 0; return null; } return item; } } public void OnExpandAllBtnClicked() { mTreeView.ExpandAllItem(); } public void OnCollapseAllBtnClicked() { mTreeView.CollapseAllItem(); } public void OnExpandBtnClicked() { TreeViewItem item = CurSelectedItem; if (item == null) { Debug.Log("Please Select a Item First"); return; } item.Expand(); } public void OnCollapseBtnClicked() { TreeViewItem item = CurSelectedItem; if (item == null) { Debug.Log("Please Select a Item First"); return; } item.Collapse(); } public void OnInsertBeforeBtnClicked() { mNewItemCount++; if (mTreeView.IsEmpty) { TreeViewItem childItem = mTreeView.InsertItem(0, "ItemPrefab1"); childItem.GetComponent().SetItemInfo("movie", "Movie" + mNewItemCount); } else { TreeViewItem item = CurSelectedItem; if (item == null) { Debug.Log("Please Select a Item First"); return; } TreeViewItem childItem = item.ParentTreeList.InsertItem(item.ItemIndex, "ItemPrefab1"); childItem.GetComponent().SetItemInfo("movie", "Movie" + mNewItemCount); } } public void OnInsertAfterBtnClicked() { mNewItemCount++; if (mTreeView.IsEmpty) { TreeViewItem childItem = mTreeView.InsertItem(0, "ItemPrefab1"); childItem.GetComponent().SetItemInfo("movie", "Movie" + mNewItemCount); } else { TreeViewItem item = CurSelectedItem; if (item == null) { Debug.Log("Please Select a Item First"); return; } TreeViewItem childItem = item.ParentTreeList.InsertItem(item.ItemIndex + 1, "ItemPrefab1"); childItem.GetComponent().SetItemInfo("movie", "Movie" + mNewItemCount); } } public void OnAddChildBtnClicked() { mNewItemCount++; if (mTreeView.IsEmpty) { TreeViewItem childItem = mTreeView.AppendItem("ItemPrefab1"); childItem.GetComponent().SetItemInfo("movie", "Movie" + mNewItemCount); } else { TreeViewItem item = CurSelectedItem; if (item == null) { Debug.Log("Please Select a Item First"); return; } TreeViewItem childItem = item.ChildTree.AppendItem("ItemPrefab1"); childItem.GetComponent().SetItemInfo("movie", "Movie" + mNewItemCount); } } public void OnDeleteBtnClicked() { TreeViewItem item = CurSelectedItem; if (item == null) { Debug.Log("Please Select a Item First"); return; } item.ParentTreeList.DeleteItem(item); } public void OnBackBtnClicked() { UnityEngine.SceneManagement.SceneManager.LoadScene("MainMenu"); } void SetRectTransformHeight(RectTransform rt,float height) { Vector2 size = rt.sizeDelta; size.y = height; rt.sizeDelta = size; } void OnTreeListRepositionFinish(TreeList treeList) { int count = treeList.ItemCount; if(count == 0) { return; } //draw the line linked from item to item TreeViewItem item0 = treeList.GetItemByIndex(0); ItemScript2 itemScript0 = item0.GetComponent(); float topY = item0.transform.localPosition.y - item0.CachedRectTransform.rect.height / 2; RectTransform rt0 = itemScript0.mLineVertical.GetComponent(); RectTransform lineRf= rt0; for (int i = 1; i< count ; ++i) { TreeViewItem item = treeList.GetItemByIndex(i); ItemScript2 itemScript = item.GetComponent(); float centerY = item.transform.localPosition.y - item.CachedRectTransform.rect.height / 2; float dist = topY - centerY; topY = centerY; RectTransform rt = itemScript.mLineVertical.GetComponent(); //set the line length SetRectTransformHeight(lineRf, dist); lineRf = rt; } SetRectTransformHeight(lineRf, 0); //draw the line linked from item to item' childTree for (int i = 0; i < count; ++i) { TreeViewItem item = treeList.GetItemByIndex(i); ItemScript2 itemScript = item.GetComponent(); RectTransform rt2 = itemScript.mLineVertical_2.GetComponent(); if (item.ChildItemCount > 0 && item.IsCollapseEnd == false) { //get the childTree's first item TreeViewItem childItem0 = item.ChildTree.GetItemByIndex(0); ItemScript2 childItemScript0 = childItem0.GetComponent(); Vector3 pos0 = item.transform.InverseTransformPoint(childItemScript0.mExpandBtn.transform.position); float dist2 = rt2.localPosition.y - pos0.y; //set the line length SetRectTransformHeight(rt2, dist2); } else { SetRectTransformHeight(rt2, 0); } } } } }