最新版本:
本文旨在让不会使用Unity的其他人员在简单了解该工具后,可以帮助研发人员搭建Unity中的UI预制体,研发人员稍作调整即可用,以减轻研发人员的工作压力。
一个UI视图的预制体的制作步骤如下:
1.在蓝湖中下载该视图的所有相关切图
2.将下载的切图资源包解压缩后,拖入到Unity中Project窗口的Assets目录中的任一文件夹内
3.选中所有切图,在Inspector窗口修改Texture Type为Sprite类型,并点击右下角的Apply
4.在顶部菜单栏SKFramework中找到LanHu,打开窗口
5.点击浏览按钮选择该视图的切图所在文件夹
6.点击创建,创建一个Canvas画布,也可以选择场景中已有的Canvas
7.添加
点击添加按钮,添加一项UI视图元素
在蓝湖中点击切图的样式信息中的内容即可复制
回到Unity,点击粘贴按钮,将从蓝湖中复制的内容粘贴到对应参数中
8.删除
点击”-“号按钮,可以将该项进行移除
点击清空按钮,可以清空当前所有的配置信息
9.收缩
配置信息过多时,点击收缩按钮,可以关闭所有折叠栏
10.展开
点击展开按钮,可以打开所有折叠栏
11.生成
点击生成后,工具会根据填写的配置信息,在切图所在文件夹中加载指定切图,并将其设置到指定位置、设置指定大小,最终将生成的UI视图创建为prefab预制体。
随着预制体的生成,工具还会将该视图的所有配置信息以资产的形式保存下来
12.导入
当想要修改一个UI视图的某一元素时,点击导入按钮,将该视图的配置资产文件进行导入,修改配置内容后重新生成即可。
13.预览生成的UI视图
打开Scene窗口中的2D选项
在Hierarchy窗口找到Canvas中的UI视图,双击聚焦查看
工具完整代码:
usingSystem; namespaceSK.Framework{ /// <summary>/// 蓝湖界面UI元素/// </summary> [Serializable] publicclassLanHuViewElement { /// <summary>/// 图层名称/// </summary>publicstringname; /// <summary>/// 位置x/// </summary>publicstringx; /// <summary>/// 位置y/// </summary>publicstringy; /// <summary>/// 宽度/// </summary>publicstringwidth; /// <summary>/// 高度/// </summary>publicstringheight; /// <summary>/// 不透明度/// </summary>publicstringopacity; /// <summary>/// 像素倍数/// </summary>publicstringpixel="x1"; /// <summary>/// 构造函数/// </summary>publicLanHuViewElement(stringname, stringx, stringy, stringwidth, stringheight, stringopacity, stringpixel) { this.name=name; this.x=x; this.y=y; this.width=width; this.height=height; this.opacity=opacity; this.pixel=pixel; } } }
usingUnityEngine; usingSystem.Collections.Generic; namespaceSK.Framework{ publicclassLanHuView : ScriptableObject { /// <summary>/// 存放切图的文件夹路径/// </summary>publicstringpath; publicList<LanHuViewElement>elements=newList<LanHuViewElement>(0); } }
usingSystem.IO; usingUnityEditor; usingUnityEngine; usingUnityEngine.UI; usingSystem.Collections.Generic; namespaceSK.Framework{ /// <summary>/// 蓝湖UI界面搭建工具/// </summary>publicclassLanHu : EditorWindow { [MenuItem("SKFramework/LanHu")] privatestaticvoidOpen() { GetWindow<LanHu>("LanHu").Show(); } privatestringpath; privateList<LanHuViewElement>elements; privateVector2scroll; privateconstfloatlabelWidth=70f; privateDictionary<LanHuViewElement, bool>foldoutDic; privateCanvasScalercanvasScaler; privatevoidOnEnable() { path="Assets"; elements=newList<LanHuViewElement>(); foldoutDic=newDictionary<LanHuViewElement, bool>(); } privatevoidOnGUI() { OnTopGUI(); OnElementsGUI(); OnMenuGUI(); } privatevoidOnTopGUI() { GUILayout.BeginHorizontal(); GUILayout.Label("切图文件夹路径:", GUILayout.Width(100f)); EditorGUILayout.TextField(path); if (GUILayout.Button("浏览", GUILayout.Width(40f))) { //Assets相对路径path=EditorUtility.OpenFolderPanel("选择切图文件夹", "", "").Replace(Application.dataPath, "Assets"); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Canvas Scaler", GUILayout.Width(100f)); canvasScaler= (CanvasScaler)EditorGUILayout.ObjectField(canvasScaler, typeof(CanvasScaler), true); if (canvasScaler==null) { if (GUILayout.Button("创建", GUILayout.Width(40f))) { varcanvas=newGameObject("Canvas").AddComponent<Canvas>(); canvas.renderMode=RenderMode.ScreenSpaceCamera; canvasScaler=canvas.gameObject.AddComponent<CanvasScaler>(); canvasScaler.uiScaleMode=CanvasScaler.ScaleMode.ScaleWithScreenSize; canvasScaler.referenceResolution=newVector2(1920f, 1080f); EditorGUIUtility.PingObject(canvas); } } GUILayout.EndHorizontal(); } privatevoidOnElementsGUI() { EditorGUILayout.Space(); GUI.enabled=canvasScaler!=null; scroll=EditorGUILayout.BeginScrollView(scroll); for (inti=0; i<elements.Count; i++) { varelement=elements[i]; if (!foldoutDic.ContainsKey(element)) { foldoutDic.Add(element, true); } foldoutDic[element] =EditorGUILayout.Foldout(foldoutDic[element], element.name, true); if (!foldoutDic[element]) continue; GUILayout.BeginVertical("Box"); GUILayout.BeginHorizontal(); GUILayout.Label("图层", GUILayout.Width(labelWidth)); element.name=EditorGUILayout.TextField(element.name); if (GUILayout.Button("粘贴", GUILayout.Width(40f))) { element.name=GUIUtility.systemCopyBuffer; } if (GUILayout.Button("-", GUILayout.Width(20f))) { foldoutDic.Remove(element); elements.RemoveAt(i); Repaint(); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("位置", GUILayout.Width(labelWidth)); element.x=EditorGUILayout.TextField(element.x); if (GUILayout.Button("粘贴", GUILayout.Width(40f))) { element.x=GUIUtility.systemCopyBuffer; } element.y=EditorGUILayout.TextField(element.y); if (GUILayout.Button("粘贴", GUILayout.Width(40f))) { element.y=GUIUtility.systemCopyBuffer; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("大小", GUILayout.Width(labelWidth)); element.width=EditorGUILayout.TextField(element.width); if (GUILayout.Button("粘贴", GUILayout.Width(40f))) { element.width=GUIUtility.systemCopyBuffer; } element.height=EditorGUILayout.TextField(element.height); if (GUILayout.Button("粘贴", GUILayout.Width(40f))) { element.height=GUIUtility.systemCopyBuffer; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("不透明度", GUILayout.Width(labelWidth)); element.opacity=EditorGUILayout.TextField(element.opacity); if (GUILayout.Button("粘贴", GUILayout.Width(40f))) { element.opacity=GUIUtility.systemCopyBuffer; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("像素倍数", GUILayout.Width(labelWidth)); if (GUILayout.Button(element.pixel)) { GenericMenugm=newGenericMenu(); gm.AddItem(newGUIContent("x1"), element.pixel=="x1", () =>element.pixel="x1"); gm.AddItem(newGUIContent("x2"), element.pixel=="x2", () =>element.pixel="x2"); gm.ShowAsContext(); } GUILayout.EndHorizontal(); GUILayout.EndVertical(); } EditorGUILayout.EndScrollView(); } privatevoidOnMenuGUI() { GUILayout.FlexibleSpace(); GUILayout.BeginHorizontal(); if (GUILayout.Button("导入", "ButtonLeft")) { stringpresetPath=EditorUtility.OpenFilePanel("选择预设文件", Application.dataPath, "asset"); if (File.Exists(presetPath)) { varimport=AssetDatabase.LoadAssetAtPath<LanHuView>(presetPath.Replace(Application.dataPath, "Assets")); if (import!=null) { elements.Clear(); foldoutDic.Clear(); path=import.path; for (inti=0; i<import.elements.Count; i++) { elements.Add(import.elements[i]); } Repaint(); } } } if (GUILayout.Button("添加", "ButtonMid")) { elements.Add(newLanHuViewElement("", "0px", "0px", "1920px", "1080px", "100%", "x1")); } if (GUILayout.Button("清空", "ButtonMid")) { if (EditorUtility.DisplayDialog("提醒", "确定删除当前所有配置信息?", "确定", "取消")) { elements.Clear(); foldoutDic.Clear(); } } if (GUILayout.Button("展开", "ButtonMid")) { for (inti=0; i<elements.Count; i++) { foldoutDic[elements[i]] =true; } } if (GUILayout.Button("收缩", "ButtonMid")) { for (inti=0; i<elements.Count; i++) { foldoutDic[elements[i]] =false; } } if (GUILayout.Button("生成", "ButtonRight")) { vararray=path.Split('/'); varview=newGameObject(array[array.Length-1]).AddComponent<RectTransform>(); view.transform.SetParent(canvasScaler.transform, false); SetRectTransform(view, 0, 0, canvasScaler.referenceResolution.x, canvasScaler.referenceResolution.y); for (inti=0; i<elements.Count; i++) { varelement=elements[i]; stringspritePath=string.Format("{0}/{1}{2}.png", path, element.name, element.pixel=="x1"?string.Empty : "@2x"); varobj=AssetDatabase.LoadAssetAtPath<Sprite>(spritePath); if (obj!=null) { varimage=newGameObject(obj.name).AddComponent<Image>(); image.transform.SetParent(view.transform, false); image.sprite=obj; RectTransformrt=image.transformasRectTransform; float.TryParse(element.x.Replace(element.x.Substring(element.x.Length-2, 2), string.Empty), outfloatxValue); float.TryParse(element.y.Replace(element.y.Substring(element.y.Length-2, 2), string.Empty), outfloatyValue); float.TryParse(element.width.Replace(element.width.Substring(element.width.Length-2, 2), string.Empty), outfloatwValue); float.TryParse(element.height.Replace(element.height.Substring(element.height.Length-2, 2), string.Empty), outfloathValue); /*float.TryParse(element.x, out float xValue);float.TryParse(element.y, out float yValue);float.TryParse(element.width, out float wValue);float.TryParse(element.height, out float hValue);*/SetRectTransform(rt, xValue, yValue, wValue, hValue); } else { Debug.Log($"<color=yellow>加载切图失败 {spritePath}</color>"); } } //创建预设文件varpreset=CreateInstance<LanHuView>(); for (inti=0; i<elements.Count; i++) { preset.elements.Add(elements[i]); } preset.path=path; AssetDatabase.CreateAsset(preset, string.Format("Assets/{0}.asset", view.name)); AssetDatabase.Refresh(); Selection.activeObject=preset; //创建Prefabvarprefab=PrefabUtility.SaveAsPrefabAsset(view.gameObject, $"Assets/{view.name}.prefab", outboolresult); if (!result) { Debug.Log($"<color=yellow>生成预制体失败 {view.name}</color>"); } else { EditorGUIUtility.PingObject(prefab); } } GUILayout.EndHorizontal(); } privatevoidSetRectTransform(RectTransformrt, floatx, floaty, floatwidth, floatheight) { //调整位置及大小rt.anchorMin=newVector2(0, 1); rt.anchorMax=newVector2(0, 1); rt.pivot=Vector2.one* .5f; rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, width); rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height); rt.anchoredPosition=newVector2(x+width/2f, -(y+height/2f)); //调整完成后自动设置锚点RectTransformprt=rt.parentasRectTransform; Vector2anchorMin=newVector2( rt.anchorMin.x+rt.offsetMin.x/prt.rect.width, rt.anchorMin.y+rt.offsetMin.y/prt.rect.height); Vector2anchorMax=newVector2( rt.anchorMax.x+rt.offsetMax.x/prt.rect.width, rt.anchorMax.y+rt.offsetMax.y/prt.rect.height); rt.anchorMin=anchorMin; rt.anchorMax=anchorMax; rt.offsetMin=rt.offsetMax=Vector2.zero; } } }