Unity 获取UI界面结构的工具

Posted lihangppz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity 获取UI界面结构的工具相关的知识,希望对你有一定的参考价值。

  开发的时候必不可少的需要要获取一个界面的子对象组件,虽然很简单但是如果每次获取都敲一次代码,也是一键很恐怖的事情。

  现在项目用了一个工具,对着界面点一下,就会导出匹配这个界面结构的类。只要初始化这个类,就可以很方便的获取这个界面子对象的组件。

  工具思路是这样的:

  1、根据子对象的命名来确定需要获取的组件。比如后缀_txt表示UILabel,_go表示GameObject。

  2、遍历所有子对象,将带后缀的子对象缓存起来。

  3、根据缓存的子对象,按照一定字符串拼接规则,写到本地脚本。

  一个界面结构和导出的界面脚本结果如下

  技术分享图片技术分享图片

  只要把界面的资源(Gameobject)传进去,就可以直接获取子对象的组件,大大提高了开发效率。当然了,工程里对这个脚本进行了一系列封装和抽象,这里是单独摘出来演示的。

  (ps:这是我第一个项目,所以不清楚其他项目怎么处理这个问题的,如果有更好的思路务必告诉我)

  闲话少说,直接上干货。(注释写的比较全,就不秀我那渣渣的表达能力了)

  工具脚本:

using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;

public class CreateSprite {
    //当前操作的对象
    private static GameObject CurGo;
    //后缀对应的组件类型
    public static Dictionary<string, string> typeMap = new Dictionary<string, string>()
    {   
        { "sp", typeof(UISprite).Name },
        { "txt", typeof(UILabel).Name },
        { "btn", typeof(UIButton).Name },
        { "go", typeof(GameObject).Name},
    };
    //脚本模版
    private static CreateSpriteUnit info;

    //在Project窗口下,选中要导出的界面,然后点击GameObject/导出脚本
    [MenuItem("GameObject/导出脚本")]
    public static void CreateSpriteAction()
    {
        GameObject[] gameObjects = Selection.gameObjects;
        //保证只有一个对象
        if (gameObjects.Length==1)
        {
            info = new CreateSpriteUnit();
            CurGo = gameObjects[0];
            ReadChild(CurGo.transform);
            info.classname = CurGo.name + "UIPanel";
            info.WtiteClass();
            info = null;
            CurGo = null;
        }
        else
        {
            EditorUtility.DisplayDialog("警告", "你只能选择一个GameObject", "确定");
        }
    }
    //遍历所有子对象,GetChild方法只能获取第一层子对象。
    public static void ReadChild(Transform tf)
    {
        foreach (Transform child in tf)
        {
            string[] typeArr = child.name.Split(_);
            if (typeArr.Length > 1)
            {
                string typeKey = typeArr[typeArr.Length - 1];
                if (typeMap.ContainsKey(typeKey))
                {
                    info.evenlist.Add(new UIInfo(child.name, typeKey, buildGameObjectPath(child).Replace(CurGo.name + "/","")));
                }

            }
            if (child.childCount > 0)
            {
                ReadChild(child);
            }
        }
    }
    //获取路径,这个路径是带当前对象名的,需要用Replace替换掉头部
    private static string buildGameObjectPath(Transform obj)
    {
        var buffer = new StringBuilder();

        while (obj != null)
        {
            if (buffer.Length > 0)
                buffer.Insert(0, "/");
            buffer.Insert(0, obj.name);
            obj = obj.parent;
        }
        return buffer.ToString();
    }
}
//导出脚本的模版
public class CreateSpriteUnit
{
    public string classname;
    public string template = @"
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class @ClassName 
{   
@fields

    public void OnAwake(GameObject viewGO)
    {
@body1
    }

    public void OnDestroy()
    {
@body2
    }
}
";
    //缓存的所有子对象信息
    public List<UIInfo> evenlist = new List<UIInfo>();
    /// <summary>
    /// 把拼接好的脚本写到本地。
    /// (自己可以个窗口支持改名和选择路径,真实工程里是带这些功能的)
    /// </summary>
    public void WtiteClass()
    {
        bool flag = true;
        bool throwOnInvalidBytes = false;
        UTF8Encoding encoding = new UTF8Encoding(flag, throwOnInvalidBytes);
        bool append = false;
        StreamWriter writer = new StreamWriter(Application.dataPath + "/" + classname + ".cs", append, encoding);
        writer.Write(GetClasss());
        writer.Close();
        AssetDatabase.Refresh();
    }
    //脚本拼接
    public string GetClasss()
    {
        var fields = new StringBuilder();
        var body1 = new StringBuilder();
        var body2 = new StringBuilder();
        for (int i = 0; i < evenlist.Count; i++)
        {
            fields.AppendLine("\\t" + evenlist[i].field);
            body1.AppendLine("\\t\\t" + evenlist[i].body1);
            body2.AppendLine("\\t\\t" + evenlist[i].body2);
        }
        template = template.Replace("@ClassName", classname).Trim();
        template = template.Replace("@body1", body1.ToString()).Trim();
        template = template.Replace("@body2", body2.ToString()).Trim();
        template = template.Replace("@fields", fields.ToString()).Trim();
        return template;
    }
}
//子对象信息
public class UIInfo{
    public string field;
    public string body1;
    public string body2;
    public UIInfo(string name, string typeKey, string path)
    {
        field = string.Format("public {0} {1};", CreateSprite.typeMap[typeKey], name);
        if (typeKey == "go")
        {
            body1 = string.Format("{0} = viewGO.transform.Find(\\"{1}\\").gameObject;", name, path, CreateSprite.typeMap[typeKey]);
        }
        else
        {
            body1 = string.Format("{0} = viewGO.transform.Find(\\"{1}\\").GetComponent<{2}>();", name, path, CreateSprite.typeMap[typeKey]);
        }
        body2 = string.Format("{0} = null;", name);
    }
}

 

 

  

技术分享图片

以上是关于Unity 获取UI界面结构的工具的主要内容,如果未能解决你的问题,请参考以下文章

Unity编辑器扩展——自动生成UI界面脚本

unity的ui文字打包后变小了

Unity之自动生成预制体脚本

Unity之自动生成预制体脚本

unity中UI界面显示FPS

Unity使用UGUI实现王者荣耀UI界面登录界面以及加载界面优化