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

Posted Hello Bug.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity编辑器扩展——自动生成UI界面脚本相关的知识,希望对你有一定的参考价值。

一:前言

对于面板赋值或Find绑定UI组件,我们可以使用一种工具化的方式去自动生成代码并绑定对象,增加效率
分为logic和view,view层是UI界面上的组件,每次都会自动生成并覆盖,logic层是逻辑


二:使用


例如一个UI界面,我们只需要做成预制体并在Project下右键预制体,选择AutoGen/Create View则会自动生成view和logic两个脚本,logic是我们要编写逻辑的脚本,view是每次都会自动生成并覆盖的脚本


三:说明

——以下几个路径都是可以自定义的(view和logic生成的路径、view和logic模版文件的路径)


——可以自定义忽略的组件类型列表


——只会生成对象名带下划线的


四:代码实现 

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

public class AutoGenCode

    //logic层代码路径
    const string LogicDir = "Assets/AutoGen/Logic";
    //view层代码路径
    const string ViewDir = "Assets/AutoGen/View";
    //logic层模版文件路径
    const string LogicTempletePath = "Assets/AutoGen/LogicTemplete.txt";
    //view层模版文件路径
    const string ViewTempletePath = "Assets/AutoGen/ViewTemplete.txt";

    //命名空间模板
    const string NameSpaceTemplete = "using 0;";
    //字段模板
    const string FieldTemplete = "public 0 1;\\t";
    //方法模板
    const string MethodTemplete = "0 = gameObject.transform.Find(\\"1\\").GetComponent<2>();\\t\\t";

    /// <summary>
    /// 忽略的组件类型列表
    /// </summary>
    static List<Type> IgnoreComponentTypeList = new List<Type>()
    
        typeof(CanvasRenderer),
        typeof(RectTransform),
    ;

    [MenuItem("Assets/AutoGen/Create View", priority = 0)]
    static void CreateLogicAndView()
    
        GameObject go = Selection.activeGameObject;
        //判断是否是prefab
        if (PrefabUtility.GetPrefabAssetType(go) != PrefabAssetType.Regular)
        
            Debug.LogWarning("选择的不是预制体,选择的对象:" + go.name);
            return;
        
        if (!Directory.Exists(ViewDir))
        
            Directory.CreateDirectory(ViewDir);
        
        if (!Directory.Exists(LogicDir))
        
            Directory.CreateDirectory(LogicDir);
        

        string className = go.name + "View";
        StringBuilder fieldContent = new StringBuilder();
        StringBuilder methodContent = new StringBuilder();
        StringBuilder nameSpaceContent = new StringBuilder();
        nameSpaceContent.AppendLine(NameSpaceTemplete.Replace("0", "UnityEngine"));//必须有UnityEngine命名空间

        string logicTempleteContent = File.ReadAllText(LogicTempletePath, Encoding.UTF8);
        string viewTempleteContent = File.ReadAllText(ViewTempletePath, Encoding.UTF8);
        string logicPath = LogicDir + "/" + go.name + "Logic.cs";
        string viewPath = ViewDir + "/" + go.name + "View.cs";

        List<string> tempNameSpaceList = new List<string>();

        //计算所有子物体组件数据
        List<ComponentInfo> infoList = new List<ComponentInfo>();
        CalcComponentInfo("", go.transform, infoList);
        foreach (var tempInfo in infoList)
        
            //字段
            string tempFieldStr = FieldTemplete.Replace("0", tempInfo.TypeStr);
            tempFieldStr = tempFieldStr.Replace("1", tempInfo.FieldName);
            fieldContent.AppendLine(tempFieldStr);

            //绑定方法
            string tempMethodStr = MethodTemplete.Replace("0", tempInfo.FieldName);
            tempMethodStr = tempMethodStr.Replace("1", tempInfo.Path);
            tempMethodStr = tempMethodStr.Replace("2", tempInfo.TypeStr);
            methodContent.AppendLine(tempMethodStr);

            //命名空间
            if (!tempNameSpaceList.Contains(tempInfo.NameSpace))
            
                string tempNameSpaceStr = NameSpaceTemplete.Replace("0", tempInfo.NameSpace);
                tempNameSpaceList.Add(tempInfo.NameSpace);
                nameSpaceContent.AppendLine(tempNameSpaceStr);
            
        

        //logic层脚本
        if (!File.Exists(logicPath))
        
            using (StreamWriter sw = new StreamWriter(logicPath))
            
                string content = logicTempleteContent;
                content = content.Replace("#CLASSNAME#", className);
                sw.Write(content);
                sw.Close();
            
        
        //view层脚本
        using (StreamWriter sw = new StreamWriter(viewPath))
        
            string content = viewTempleteContent;
            content = content.Replace("#NAMESPACE#", nameSpaceContent.ToString());
            content = content.Replace("#CLASSNAME#", className);
            content = content.Replace("#FIELD_BIND#", fieldContent.ToString());
            content = content.Replace("#METHOD_BIND#", methodContent.ToString());
            sw.Write(content);
            sw.Close();
        

        AssetDatabase.Refresh();
    

    /// <summary>
    /// 计算所有子物体组件数据
    /// </summary>
    static void CalcComponentInfo(string path, Transform child, List<ComponentInfo> infoList)
    
        bool isRoot = string.IsNullOrEmpty(path);
        if (!isRoot
            && IsVaildField(child.name))
        
            var componentList = child.GetComponents<Component>();
            foreach (var tempComponent in componentList)
            
                ComponentInfo info = new ComponentInfo()
                
                    Path = path,
                    go = child.gameObject,
                    NameSpace = tempComponent.GetType().Namespace,
                    TypeStr = tempComponent.GetType().Name,
                ;
                if (!HaveSameComponentInfo(info, infoList)
                    && !IgnoreComponentTypeList.Contains(tempComponent.GetType()))
                
                    infoList.Add(info);
                
            
        

        foreach (Transform tempTrans in child.transform)
        
            CalcComponentInfo(isRoot ? tempTrans.name : path + "/" + tempTrans.name, tempTrans.transform, infoList);
        
    

    /// <summary>
    /// 是否为合法的字段名
    /// </summary>
    static bool IsVaildField(string goName)
    
        if (goName.Contains("_"))
        
            if (int.TryParse(goName[0].ToString(), out _))
            
                Debug.LogWarning("字段名不能以数字开头:, goName :" + goName);
                return false;
            
            return true;
        
        return false;
    

    /// <summary>
    /// 是否有相同的组件数据
    /// </summary>
    static bool HaveSameComponentInfo(ComponentInfo info, List<ComponentInfo> infoList)
    
        foreach (var tempInfo in infoList)
        
            if (tempInfo.FieldName == info.FieldName)
            
                Debug.LogWarning("子物体名重复:, goName :" + info.go.name);
                return true;
            
        
        return false;
    


/// <summary>
/// 组件数据
/// </summary>
public class ComponentInfo

    public string Path;
    public GameObject go;
    public string NameSpace;
    public string TypeStr;
    public string FieldName
    
        get
        
            return $"go.name_TypeStr";
        
    

以上是关于Unity编辑器扩展——自动生成UI界面脚本的主要内容,如果未能解决你的问题,请参考以下文章

Unity编辑器扩展

Unity3D编辑器扩展Unity3D中实现UI界面控制,UI界面的显示和隐藏实现

Unity UGUI - Canvas 画布

Unity UGUI - Canvas 画布

Unity编辑器扩展

unity UI如何开启(显示)或者关闭(隐藏)Panel界面最好?