效果
全为一键生成
实现自动生成代码绑定UI控件 并生成字典保存UI控件
减少自己拖拽 和手动书写过程 适用动态加载面板
建议搭配UI框架使用
实现思路
根据当前选中的gameobject 查找其下方是否有对应类型的控件 有就保存到字典中 然后通过向上递归拼凑地址,然后生成到粘贴板 直接粘贴到目标位置即可
实现过程
Selection.gameObjects会获取当前选中的物体数组 我们取出第一个即可
这个字典专门用来存放 我们需要获取的类型和该类型在代码里面的前缀
如 名字叫 AddButton的物体身上的button组件 获取后在代码里面的名字为 btnAddbutton
根据刚才字典的键,就是我们要获取的类型 遍历选中物体下所有子物体是否有该类型的组件 有就存放到字典 改字典的 键是
该控件物体的地址如
值是控件类型
至于为什么要这样做后面会解释
找到当前foreach循环类型的组件后 会保存到component数组里面 开始拼凑地址 凑地址之前会进行判断 如果后缀 不是自定义的字符串 就不进行生成
这样增加灵活性
然后开始拼凑当前component[i]的地址
(清除后缀 如LoadPlace_Auto会切割为 LoadPlace作为真实名字保存为临时变量 在声明变量时使用)
思路是while循环 当父物体不为选中物体是就一直向上循环拼凑字符串
加入字典的时候为什么要把键 设置为简称加上地址呢
因为如果键是地址的话 如果这个物体上同时拥有 image和text那键就重复了 都是xxx/xxx/xxx
所有改成简称加上地址 这样找到的image在字典中就是 imgxxx/xxx/xxx 不会重复
完成循环后 我们的字典里面已经找到了所有我们需要自动绑定的UI控件
键值对形式为 控件检测+地址,真实控件实例
然后开始生成代码
通过/来分割字符串 获取字符串的最后一位
如LoadPlace_auto这个物体的上的image组件 的键就为 imgLeft/CargoShow/LoadPlace_Auto
我们直接用/切割字符串
获取最后一位 即LoadPlace_Auto
这样不会出现问题
但如果LoadPlace_Auto 在选中的PlaningPanel下面第一位
键就会变为imgLoadPlace_Auto 这样/切割就会失效 会出bug
所以我们加一个判断 如果切割后只有一位长度 那就要去除前缀
这样才能拿到真实的名字
切割到前面的前缀 获取真实的地址
根据我们的命名规则 拼凑代码中的命名文章来源:https://www.toymoban.com/news/detail-855792.html
然后生成到粘贴板即可文章来源地址https://www.toymoban.com/news/detail-855792.html
代码如下
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System; using UnityEngine.UI; using System.Text; using TMPro; public class UIBindingTool : Editor { private static string endWith = "_Auto"; /// <summary> /// 简称+真实地址 类型 /// </summary> private static Dictionary<string, Type> findDic = new Dictionary<string, Type>();//保存已经找到的控件 类型名字简称+真实地址 类型 原因防止key重复并且都是3位好处理 private static Dictionary<Type, string> dicMap = GenerateBtuDic(); [MenuItem("GameObject/GenerateBinding", false, 1)] private static void GenerateBinding() { if (Selection.gameObjects.Length < 1)//返回当前在Hierarchy面板上或Project文件夹下选择的游戏物体GameObject数组,未选择则数组长度则为0 return; GameObject selectObj = Selection.gameObjects[0];//找到选中的第一个物体 //foreach (var item in Selection.gameObjects) //{ // Debug.Log(item.name); //} //if (dicMap == null) ; //Dictionary<Type, string> dicMap = GenerateBtuDic();//控件类型对应的名字字典 StringBuilder pasteContent = new StringBuilder(); //声明保存的字典 //rider不要\t // pasteContent.Append("\t#region 自动绑定\n"); pasteContent.Append("#region 自动绑定\n"); pasteContent.Append("\tprivate Dictionary<string, UIBehaviour> componentsDic = new Dictionary<string, UIBehaviour>();\n"); foreach (Type type in dicMap.Keys)//看看物体上有没有对应类型的控件 keys是UI组件类型 { //获取子物体上所有对应UI组件 Component[] components = selectObj.GetComponentsInChildren(type);//GetComponentsInChildren可以获取到儿子孙子 深度优先 包含自己 if (components.Length < 1) continue;//没有获取到就下一个 for (int i = 0; i < components.Length; i++) { //if (!components[i].name.StartsWith(startsWith)) if (!components[i].name.EndsWith(endWith)) continue;// 加一个字符串条件判断 //满足条件 Component component = components[i]; //组件的名字 string name = dicMap[type] + component.name.Substring(0, component.name.Length - endWith.Length); //组件的地址 string path = component.name; Transform transform = component.transform; //构成控件的path while (!transform.parent.name.Equals(selectObj.name))//中间的地址 { //Debug.Log(transform.name); path = transform.parent.name + "/" + path; transform = transform.parent; } //地址=父物体名字+中间地址+名字 //Debug.Log(selectObj.name +"/"+ path); findDic.Add(dicMap[type] + /*selectObj.name + "/" +*/ path, type); //Debug.Log(dicMap[type] + /*selectObj.name + "/" +*/ path); //组件的声明 pasteContent.Append("\t"+"private" + "\t" + type.Name + "\t" + name + ";"); pasteContent.Append("\n"); } //Debug.Log(pasteContent); } pasteContent.Append("\t#endregion\n"); //查找组件 pasteContent.Append("\t//自动获取组件添加字典管理"); pasteContent.Append("\n"); pasteContent.Append("\tprivate void AutoBindingUI()"); pasteContent.Append("\n"); pasteContent.Append("\t{"); foreach (string item in findDic.Keys) { //!!!直接在选中物体下面的会有Bug!!! 如果一共就一位 先去掉前缀再继续 string[] temp = item.Split("/"); string componentName; if (temp.Length > 1) //获取真实名字 componentName = temp[temp.Length - 1]; else componentName = temp[temp.Length - 1].Substring(dicMap[findDic[item]].Length); //获取真实地址 Bug string realPath = item.Substring(dicMap[findDic[item]].Length); //拼接变量名 string varName = dicMap[findDic[item]] + componentName.Substring(0, componentName.Length - endWith.Length); //Debug.Log(componentName.Substring(0, componentName.Length - endWith.Length)); //Debug.Log(componentName + " " + realPath + " " + varName); //语句 pasteContent.Append("\n"); pasteContent.Append($"\t\t{varName} = transform.Find(\"{realPath}\").GetComponent<{findDic[item].Name}>();"); //rigidbody = transform.Find().GetComponent<>(); } //加入字典 foreach (string item in findDic.Keys) { //!!!直接在选中物体下面的会有Bug!!! 如果一共就一位 先去掉前缀再继续 string[] temp = item.Split("/"); string componentName; if (temp.Length > 1) //获取真实名字 componentName = temp[temp.Length - 1]; else componentName = temp[temp.Length - 1].Substring(dicMap[findDic[item]].Length); //拼接变量名 string varName = dicMap[findDic[item]] + componentName.Substring(0, componentName.Length - endWith.Length); //Debug.Log(componentName.Substring(0, componentName.Length - endWith.Length)); //Debug.Log(componentName + " " + realPath + " " + varName); //语句 pasteContent.Append("\n"); pasteContent.Append($"\t\tcomponentsDic.Add(\"{varName.ToString()}\", {varName});"); //componentsDic.Add(inputPlaneID.ToString(), inputPlaneID); } //TODO:生成封装组件事件的方法 pasteContent.Append("\n"); pasteContent.Append("\t}"); TextEditor text = new TextEditor(); text.text = pasteContent.ToString(); text.SelectAll(); text.Copy(); Debug.Log("生成成功"); } private static Dictionary<Type, string> GenerateBtuDic()//寻找里面有没有我定义的类型的键(key)匹配,然后返回我对应的类型? { Dictionary<Type, string> dic = new Dictionary<Type, string>(); dic.Add(typeof(Button), "btn"); dic.Add(typeof(Scrollbar), "scrB"); dic.Add(typeof(Image), "img"); dic.Add(typeof(TMP_InputField), "input"); dic.Add(typeof(VerticalLayoutGroup), "layoutGRP"); dic.Add(typeof(Text), "text"); dic.Add(typeof(TMP_Text), "texT"); dic.Add(typeof(GridLayoutGroup), "layout"); dic.Add(typeof(TMP_Dropdown), "dropD"); return dic; } }
到了这里,关于Unity UGUI一键绑定UI控件工具(编辑器拓展)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!