前言
本文针对使用Unity3D UGUI进行UI开发所遇到的痛点。
- 痛点:
在使用UGUI进行UI开发时,我们往往需要查找相关UI物件的引用,然后保存起来重复使用;
虽然简单,但是如果UI结构比较复杂了之后,每次都要去挨个生成变量,然后对应路径找其引用,若其中一不小心还容易输出一两个字母,费时又费力。 - 解决:
开发一个小工具,针对我们自己所需的代码模版,可以快速生成代码供我们复制,既不会出错,同时在UI量多了之后可以大大减少我们书写代码的工作量。
首先要会一点关于Unity3D编辑器扩展的知识,如果不是很了解,可以看我相关的文章,相信你看一遍就恍然大悟,自己也可以根据自己的需求完成相关小工具开发了。
开发思路
UGUI UI工作流:我们使用UGUI做UI,往往是将UI拼接好,然后保存成Prefab,再通过代码加载Prefab,并通过获取Prefab实例上需要动态修改的UI节点引用,进行动态操作。
- 标记需要保存引用的UI节点。 我们这里采用将选中的UI节点的Name前后分别加上"["与"]"符号。例如:CommitBtn标记后为:[CommitBtn]
- 标记UI节点后,保存修改到Prefab,选中相应Prefab,右键GenCode选项,弹出窗口根据我们代码模块生成代码。
- 分析我们所需的代码模块:例如我这里是在Lua中使用,形如:self.commitBtn=self:FindChild("...");
功能实现
- 在Hierarchy面板选中物件,右键Mark选项,标记物件。或者UnMark选项,取消标记。
[MenuItem("GameObject/Mark",false,11)]
static void AddTag()
{
GameObject[] curArr = Selection.gameObjects;
if(curArr.Length!=0)
{
for(int i=0;i<curArr.Length;i++)
{
if(!curArr[i].name.StartsWith("["))
{
Undo.RecordObject(curArr[i],"AddTag");
curArr[i].name="["+curArr[i].name+"]";
}
}
}
}
[MenuItem("GameObject/UnMark",false,11)]
static void RemoveTag()
{
GameObject[] curArr=Selection.gameObjects;
if(curArr.Length!=0)
{
for (int i=0;i<curArr.Length;i++)
{
Undo.RecordObject(curArr[i],"RemoveTag");
curArr[i].name=curArr[i].name.Replace("[","");
curArr[i].name=curArr[i].name.Replace("]","");
}
}
}
- 根据所需代码模块,右键Prefab,GenCode选项,弹窗,批量生成标记物件的相关操作代码
[MenuItem("Assets/GenCode",true)]
static bool IsCanDo()
{
if(PrefabUtility.GetPrefabAssetType(Selection.activeObject)==PrefabAssetType.Regular)
{
return true;
}
return false;
}
//此处使用str拼接,可以通过文件操作读取代码模版,进行输出
static string str="";
[MenuItem("Assets/GenCode",false)]
static void GenCode()
{
GameObject curGO = Selection.activeObject as GameObject;
str="";
GenerateCode(curGO.transform,"");
MarkTools codeWindow = EditorWindow.GetWindow<MarkTools>("Generate Code");
codeWindow.Show();
}
static void GenerateCode(Transform tf,string path)
{
if(tf==null)
return;
for(int i=0;i<tf.childCount;i++)
{
string curName = tf.GetChild(i).name;
string curPath = path + curName;
if(curName.StartsWith("[") && curName.EndsWith("]"))
{
str+="self.";
string varName= GetStanardVarName(curName);
str += varName + "= self:FindChild(\"" + curPath + "\"";
str += "\n";
}
GenerateCode(tf.GetChild(i),curPath + "/");
}
}
static string GetStanardVarName(string name)
{
//去掉"["和"]"
name = name.Substring(1, name.Length - 2);
string firstAlpha = name[0].ToString().ToLower();
name = firstAlpha + name.Substring(1);
return name;
}
void OnGUI()
{
EditorGUILayout.TextArea(str);
}
扩展:以上都是使用最简陋的方法实现批量生成标记物件代码,可以通过文件操作读取你自己的代码模板,生成更加标准的代码。甚至还可以添加增量生成等更进一步的优化。
完整代码
using UnityEngine;
using UnityEditor;
public class MarkTools:EditorWindow
{
[MenuItem("GameObject/Mark",false,11)]
static void AddTag()
{
GameObject[] curArr = Selection.gameObjects;
if(curArr.Length!=0)
{
for(int i=0;i<curArr.Length;i++)
{
if(!curArr[i].name.StartsWith("["))
{
Undo.RecordObject(curArr[i],"AddTag");
curArr[i].name="["+curArr[i].name+"]";
}
}
}
}
[MenuItem("GameObject/UnMark",false,11)]
static void RemoveTag()
{
GameObject[] curArr=Selection.gameObjects;
if(curArr.Length!=0)
{
for (int i=0;i<curArr.Length;i++)
{
Undo.RecordObject(curArr[i],"RemoveTag");
curArr[i].name=curArr[i].name.Replace("[","");
curArr[i].name=curArr[i].name.Replace("]","");
}
}
}
[MenuItem("Assets/GenCode",true)]
static bool IsCanDo()
{
if(PrefabUtility.GetPrefabAssetType(Selection.activeObject)==PrefabAssetType.Regular)
{
return true;
}
return false;
}
static string str="";
[MenuItem("Assets/GenCode",false)]
static void GenCode()
{
GameObject curGO = Selection.activeObject as GameObject;
str="";
GenerateCode(curGO.transform,"");
MarkTools codeWindow = EditorWindow.GetWindow<MarkTools>("Generate Code");
codeWindow.Show();
}
static void GenerateCode(Transform tf,string path)
{
if(tf==null)
return;
for(int i=0;i<tf.childCount;i++)
{
string curName = tf.GetChild(i).name;
string curPath = path + curName;
if(curName.StartsWith("[") && curName.EndsWith("]"))
{
str+="self.";
string varName= GetStanardVarName(curName);
str += varName + "= self:FindChild(\"" + curPath + "\"";
str += "\n";
}
GenerateCode(tf.GetChild(i),curPath + "/");
}
}
static string GetStanardVarName(string name)
{
//去掉"["和"]"
name = name.Substring(1, name.Length - 2);
string firstAlpha = name[0].ToString().ToLower();
name = firstAlpha + name.Substring(1);
return name;
}
void OnGUI()
{
EditorGUILayout.TextArea(str);
}
}
总结
通过以上的扩展工具,我们在使用UGUI的时候能够节省不少的代码工作量,并且不会再出现输入的误差。
但是他只是一个非常粗糙的工具,还需要更进一步优化和修改成你自己所需的工具,这里只是做一个抛砖引用。
优化路线:1.需要支持代码模版,2.需要添加增量优化(生成你以前没有生成过的代码,而不是所有的都生成),3.可否直接生成完整代码,而不是代码片段。