Unity & 蓝湖 关于UI工作流优化的思考(二)

举报
CoderZ1010 发表于 2022/09/25 05:26:15 2022/09/25
【摘要】 背景和历史版本在下面这篇博客中查看: Unity & 蓝湖 关于UI工作流优化的思考 最新版本: 本文旨在让不会使用Unity的其他人员在简单了解该工具后,可以帮助研发人员搭建Unity中的UI预制体,研发人员稍作调整即可用,以减轻研发人员的工作压力。 一个UI视图的预制体的制作步骤如下: 1.在蓝湖中下载...

背景和历史版本在下面这篇博客中查看:

Unity & 蓝湖 关于UI工作流优化的思考

最新版本:

本文旨在让不会使用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视图,双击聚焦查看

工具完整代码:


  
  1. using System;
  2. namespace SK.Framework
  3. {
  4. /// <summary>
  5. /// 蓝湖界面UI元素
  6. /// </summary>
  7. [Serializable]
  8. public class LanHuViewElement
  9. {
  10. /// <summary>
  11. /// 图层名称
  12. /// </summary>
  13. public string name;
  14. /// <summary>
  15. /// 位置x
  16. /// </summary>
  17. public string x;
  18. /// <summary>
  19. /// 位置y
  20. /// </summary>
  21. public string y;
  22. /// <summary>
  23. /// 宽度
  24. /// </summary>
  25. public string width;
  26. /// <summary>
  27. /// 高度
  28. /// </summary>
  29. public string height;
  30. /// <summary>
  31. /// 不透明度
  32. /// </summary>
  33. public string opacity;
  34. /// <summary>
  35. /// 像素倍数
  36. /// </summary>
  37. public string pixel = "x1";
  38. /// <summary>
  39. /// 构造函数
  40. /// </summary>
  41. public LanHuViewElement(string name, string x, string y, string width, string height, string opacity, string pixel)
  42. {
  43. this.name = name;
  44. this.x = x;
  45. this.y = y;
  46. this.width = width;
  47. this.height = height;
  48. this.opacity = opacity;
  49. this.pixel = pixel;
  50. }
  51. }
  52. }

  
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. namespace SK.Framework
  4. {
  5. public class LanHuView : ScriptableObject
  6. {
  7. /// <summary>
  8. /// 存放切图的文件夹路径
  9. /// </summary>
  10. public string path;
  11. public List<LanHuViewElement> elements = new List<LanHuViewElement>(0);
  12. }
  13. }

  
  1. using System.IO;
  2. using UnityEditor;
  3. using UnityEngine;
  4. using UnityEngine.UI;
  5. using System.Collections.Generic;
  6. namespace SK.Framework
  7. {
  8. /// <summary>
  9. /// 蓝湖UI界面搭建工具
  10. /// </summary>
  11. public class LanHu : EditorWindow
  12. {
  13. [MenuItem("SKFramework/LanHu")]
  14. private static void Open()
  15. {
  16. GetWindow<LanHu>("LanHu").Show();
  17. }
  18. private string path;
  19. private List<LanHuViewElement> elements;
  20. private Vector2 scroll;
  21. private const float labelWidth = 70f;
  22. private Dictionary<LanHuViewElement, bool> foldoutDic;
  23. private CanvasScaler canvasScaler;
  24. private void OnEnable()
  25. {
  26. path = "Assets";
  27. elements = new List<LanHuViewElement>();
  28. foldoutDic = new Dictionary<LanHuViewElement, bool>();
  29. }
  30. private void OnGUI()
  31. {
  32. OnTopGUI();
  33. OnElementsGUI();
  34. OnMenuGUI();
  35. }
  36. private void OnTopGUI()
  37. {
  38. GUILayout.BeginHorizontal();
  39. GUILayout.Label("切图文件夹路径:", GUILayout.Width(100f));
  40. EditorGUILayout.TextField(path);
  41. if (GUILayout.Button("浏览", GUILayout.Width(40f)))
  42. {
  43. //Assets相对路径
  44. path = EditorUtility.OpenFolderPanel("选择切图文件夹", "", "").Replace(Application.dataPath, "Assets");
  45. }
  46. GUILayout.EndHorizontal();
  47. GUILayout.BeginHorizontal();
  48. GUILayout.Label("Canvas Scaler", GUILayout.Width(100f));
  49. canvasScaler = (CanvasScaler)EditorGUILayout.ObjectField(canvasScaler, typeof(CanvasScaler), true);
  50. if (canvasScaler == null)
  51. {
  52. if (GUILayout.Button("创建", GUILayout.Width(40f)))
  53. {
  54. var canvas = new GameObject("Canvas").AddComponent<Canvas>();
  55. canvas.renderMode = RenderMode.ScreenSpaceCamera;
  56. canvasScaler = canvas.gameObject.AddComponent<CanvasScaler>();
  57. canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
  58. canvasScaler.referenceResolution = new Vector2(1920f, 1080f);
  59. EditorGUIUtility.PingObject(canvas);
  60. }
  61. }
  62. GUILayout.EndHorizontal();
  63. }
  64. private void OnElementsGUI()
  65. {
  66. EditorGUILayout.Space();
  67. GUI.enabled = canvasScaler != null;
  68. scroll = EditorGUILayout.BeginScrollView(scroll);
  69. for (int i = 0; i < elements.Count; i++)
  70. {
  71. var element = elements[i];
  72. if (!foldoutDic.ContainsKey(element))
  73. {
  74. foldoutDic.Add(element, true);
  75. }
  76. foldoutDic[element] = EditorGUILayout.Foldout(foldoutDic[element], element.name, true);
  77. if (!foldoutDic[element]) continue;
  78. GUILayout.BeginVertical("Box");
  79. GUILayout.BeginHorizontal();
  80. GUILayout.Label("图层", GUILayout.Width(labelWidth));
  81. element.name = EditorGUILayout.TextField(element.name);
  82. if (GUILayout.Button("粘贴", GUILayout.Width(40f)))
  83. {
  84. element.name = GUIUtility.systemCopyBuffer;
  85. }
  86. if (GUILayout.Button("-", GUILayout.Width(20f)))
  87. {
  88. foldoutDic.Remove(element);
  89. elements.RemoveAt(i);
  90. Repaint();
  91. }
  92. GUILayout.EndHorizontal();
  93. GUILayout.BeginHorizontal();
  94. GUILayout.Label("位置", GUILayout.Width(labelWidth));
  95. element.x = EditorGUILayout.TextField(element.x);
  96. if (GUILayout.Button("粘贴", GUILayout.Width(40f)))
  97. {
  98. element.x = GUIUtility.systemCopyBuffer;
  99. }
  100. element.y = EditorGUILayout.TextField(element.y);
  101. if (GUILayout.Button("粘贴", GUILayout.Width(40f)))
  102. {
  103. element.y = GUIUtility.systemCopyBuffer;
  104. }
  105. GUILayout.EndHorizontal();
  106. GUILayout.BeginHorizontal();
  107. GUILayout.Label("大小", GUILayout.Width(labelWidth));
  108. element.width = EditorGUILayout.TextField(element.width);
  109. if (GUILayout.Button("粘贴", GUILayout.Width(40f)))
  110. {
  111. element.width = GUIUtility.systemCopyBuffer;
  112. }
  113. element.height = EditorGUILayout.TextField(element.height);
  114. if (GUILayout.Button("粘贴", GUILayout.Width(40f)))
  115. {
  116. element.height = GUIUtility.systemCopyBuffer;
  117. }
  118. GUILayout.EndHorizontal();
  119. GUILayout.BeginHorizontal();
  120. GUILayout.Label("不透明度", GUILayout.Width(labelWidth));
  121. element.opacity = EditorGUILayout.TextField(element.opacity);
  122. if (GUILayout.Button("粘贴", GUILayout.Width(40f)))
  123. {
  124. element.opacity = GUIUtility.systemCopyBuffer;
  125. }
  126. GUILayout.EndHorizontal();
  127. GUILayout.BeginHorizontal();
  128. GUILayout.Label("像素倍数", GUILayout.Width(labelWidth));
  129. if (GUILayout.Button(element.pixel))
  130. {
  131. GenericMenu gm = new GenericMenu();
  132. gm.AddItem(new GUIContent("x1"), element.pixel == "x1", () => element.pixel = "x1");
  133. gm.AddItem(new GUIContent("x2"), element.pixel == "x2", () => element.pixel = "x2");
  134. gm.ShowAsContext();
  135. }
  136. GUILayout.EndHorizontal();
  137. GUILayout.EndVertical();
  138. }
  139. EditorGUILayout.EndScrollView();
  140. }
  141. private void OnMenuGUI()
  142. {
  143. GUILayout.FlexibleSpace();
  144. GUILayout.BeginHorizontal();
  145. if (GUILayout.Button("导入", "ButtonLeft"))
  146. {
  147. string presetPath = EditorUtility.OpenFilePanel("选择预设文件", Application.dataPath, "asset");
  148. if (File.Exists(presetPath))
  149. {
  150. var import = AssetDatabase.LoadAssetAtPath<LanHuView>(presetPath.Replace(Application.dataPath, "Assets"));
  151. if (import != null)
  152. {
  153. elements.Clear();
  154. foldoutDic.Clear();
  155. path = import.path;
  156. for (int i = 0; i < import.elements.Count; i++)
  157. {
  158. elements.Add(import.elements[i]);
  159. }
  160. Repaint();
  161. }
  162. }
  163. }
  164. if (GUILayout.Button("添加", "ButtonMid"))
  165. {
  166. elements.Add(new LanHuViewElement("", "0px", "0px", "1920px", "1080px", "100%", "x1"));
  167. }
  168. if (GUILayout.Button("清空", "ButtonMid"))
  169. {
  170. if (EditorUtility.DisplayDialog("提醒", "确定删除当前所有配置信息?", "确定", "取消"))
  171. {
  172. elements.Clear();
  173. foldoutDic.Clear();
  174. }
  175. }
  176. if (GUILayout.Button("展开", "ButtonMid"))
  177. {
  178. for (int i = 0; i < elements.Count; i++)
  179. {
  180. foldoutDic[elements[i]] = true;
  181. }
  182. }
  183. if (GUILayout.Button("收缩", "ButtonMid"))
  184. {
  185. for (int i = 0; i < elements.Count; i++)
  186. {
  187. foldoutDic[elements[i]] = false;
  188. }
  189. }
  190. if (GUILayout.Button("生成", "ButtonRight"))
  191. {
  192. var array = path.Split('/');
  193. var view = new GameObject(array[array.Length - 1]).AddComponent<RectTransform>();
  194. view.transform.SetParent(canvasScaler.transform, false);
  195. SetRectTransform(view, 0, 0, canvasScaler.referenceResolution.x, canvasScaler.referenceResolution.y);
  196. for (int i = 0; i < elements.Count; i++)
  197. {
  198. var element = elements[i];
  199. string spritePath = string.Format("{0}/{1}{2}.png", path, element.name, element.pixel == "x1" ? string.Empty : "@2x");
  200. var obj = AssetDatabase.LoadAssetAtPath<Sprite>(spritePath);
  201. if (obj != null)
  202. {
  203. var image = new GameObject(obj.name).AddComponent<Image>();
  204. image.transform.SetParent(view.transform, false);
  205. image.sprite = obj;
  206. RectTransform rt = image.transform as RectTransform;
  207. float.TryParse(element.x.Replace(element.x.Substring(element.x.Length - 2, 2), string.Empty), out float xValue);
  208. float.TryParse(element.y.Replace(element.y.Substring(element.y.Length - 2, 2), string.Empty), out float yValue);
  209. float.TryParse(element.width.Replace(element.width.Substring(element.width.Length - 2, 2), string.Empty), out float wValue);
  210. float.TryParse(element.height.Replace(element.height.Substring(element.height.Length - 2, 2), string.Empty), out float hValue);
  211. /*
  212. float.TryParse(element.x, out float xValue);
  213. float.TryParse(element.y, out float yValue);
  214. float.TryParse(element.width, out float wValue);
  215. float.TryParse(element.height, out float hValue);
  216. */
  217. SetRectTransform(rt, xValue, yValue, wValue, hValue);
  218. }
  219. else
  220. {
  221. Debug.Log($"<color=yellow>加载切图失败 {spritePath}</color>");
  222. }
  223. }
  224. //创建预设文件
  225. var preset = CreateInstance<LanHuView>();
  226. for (int i = 0; i < elements.Count; i++)
  227. {
  228. preset.elements.Add(elements[i]);
  229. }
  230. preset.path = path;
  231. AssetDatabase.CreateAsset(preset, string.Format("Assets/{0}.asset", view.name));
  232. AssetDatabase.Refresh();
  233. Selection.activeObject = preset;
  234. //创建Prefab
  235. var prefab = PrefabUtility.SaveAsPrefabAsset(view.gameObject, $"Assets/{view.name}.prefab", out bool result);
  236. if (!result)
  237. {
  238. Debug.Log($"<color=yellow>生成预制体失败 {view.name}</color>");
  239. }
  240. else
  241. {
  242. EditorGUIUtility.PingObject(prefab);
  243. }
  244. }
  245. GUILayout.EndHorizontal();
  246. }
  247. private void SetRectTransform(RectTransform rt, float x, float y, float width, float height)
  248. {
  249. //调整位置及大小
  250. rt.anchorMin = new Vector2(0, 1);
  251. rt.anchorMax = new Vector2(0, 1);
  252. rt.pivot = Vector2.one * .5f;
  253. rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, width);
  254. rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height);
  255. rt.anchoredPosition = new Vector2(x + width / 2f, -(y + height / 2f));
  256. //调整完成后自动设置锚点
  257. RectTransform prt = rt.parent as RectTransform;
  258. Vector2 anchorMin = new Vector2(
  259. rt.anchorMin.x + rt.offsetMin.x / prt.rect.width,
  260. rt.anchorMin.y + rt.offsetMin.y / prt.rect.height);
  261. Vector2 anchorMax = new Vector2(
  262. rt.anchorMax.x + rt.offsetMax.x / prt.rect.width,
  263. rt.anchorMax.y + rt.offsetMax.y / prt.rect.height);
  264. rt.anchorMin = anchorMin;
  265. rt.anchorMax = anchorMax;
  266. rt.offsetMin = rt.offsetMax = Vector2.zero;
  267. }
  268. }
  269. }

文章来源: coderz.blog.csdn.net,作者:CoderZ1010,版权归原作者所有,如需转载,请联系作者。

原文链接:coderz.blog.csdn.net/article/details/124320434

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。