我们Unity项目关于UI界面制作的工作流是这样的,UI设计人员将设计好的UI界面在Adobe XD中上传至蓝湖,Unity程序猿从蓝湖中下载切图资源包导入项目工程中,根据蓝湖中的效果图、样式信息进行界面的搭建:

例如这张首页UI中的第一个按钮,其图层名称为"组646",位置为(209px,605px),大小为(225px,76px)

首先可以看到位置信息中的685px是指这个图层到顶部的像素大小,可以判断其位置信息是在以左上角为原点的坐标系中的,而且在Unity中RectTransform组件以(0.5,0.5)为默认的轴心点,因此在考虑横坐标时需要计算上该图层宽度的一半,考虑纵坐标时需要计算上该图层高度的一半:

以这个按钮图层为例,在Unity中我们将其RectTransform组件中的锚点设为左上角,Pivot轴心点使用默认的(0.5,0.5),则其横坐标则是209+225 * 0.5,纵坐标则是-(685 + 76 * 0.5),计算出结果为(321.5,-723):

有了这样的换算关系后,基于能偷懒则偷懒的原则,我开始思考将其转化为自动化的过程,于是写了这样一个工具,只需要在工具中输入蓝湖中该图层的位置及大小信息,点击确定即可将该按钮设置正确的位置及大小:

代码如下:

using UnityEngine;
using UnityEditor;
using UnityEngine.UI;namespace SK.Framework
{public class LanHu : EditorWindow{[MenuItem("SKFramework/Tools/Lan Hu")]private static void Open(){GetWindow<LanHu>("蓝湖").Show();}private const float labelWidth = 60f;private float x;private float y;private float width;private float height;private void OnGUI(){//如果未选中任何物体 returnif (Selection.activeTransform == null) return;RectTransform rt = Selection.activeTransform.GetComponent<RectTransform>();//如果选中的物体不是UI元素 returnif (rt == null) return;GUILayout.Label("分辨率: 1920*1080");EditorGUILayout.Space();GUILayout.Label("样式信息", "BoldLabel");GUILayout.BeginHorizontal();GUILayout.Label("图层", GUILayout.Width(labelWidth));var image = rt.GetComponent<Image>();if (image != null && image.sprite != null) EditorGUILayout.TextField(image.sprite.name);else EditorGUILayout.HelpBox("未发现任何图层", MessageType.Warning);GUILayout.EndHorizontal();GUILayout.BeginHorizontal();GUILayout.Label("位置", GUILayout.Width(labelWidth));x = EditorGUILayout.FloatField(x);GUILayout.Label("px");y = EditorGUILayout.FloatField(y);GUILayout.Label("px");GUILayout.EndHorizontal();GUILayout.BeginHorizontal();GUILayout.Label("大小", GUILayout.Width(labelWidth));width = EditorGUILayout.FloatField(width);GUILayout.Label("px");height = EditorGUILayout.FloatField(height);GUILayout.Label("px");GUILayout.EndHorizontal();GUILayout.FlexibleSpace();if (GUILayout.Button("确定")){//调整位置及大小rt.anchorMin = new Vector2(0, 1);rt.anchorMax = new Vector2(0, 1);rt.pivot = Vector2.one * .5f;rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, width);rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height);rt.anchoredPosition = new Vector2(x + width / 2f, -(y + height / 2f));//调整完成后自动设置锚点RectTransform prt = rt.parent as RectTransform;Vector2 anchorMin = new Vector2(rt.anchorMin.x + rt.offsetMin.x / prt.rect.width,rt.anchorMin.y + rt.offsetMin.y / prt.rect.height);Vector2 anchorMax = new Vector2(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;EditorUtility.SetDirty(rt);}}private void OnSelectionChange(){Repaint();}}
}

以上是在这条偷懒路上的第一个产物,它依然需要手动输入图层的位置、大小信息,随后发现了蓝湖中的这些样式信息是可以点击复制的:

于是我开始思考将float类型的输入框改为string类型的输入框,将复制来的信息直接粘贴到输入框中,只需要将字符串的最后两个字符px移除,再将其转化为float类型即可,于是有了第二个产物:

代码如下:

using UnityEngine;
using UnityEditor;
using UnityEngine.UI;namespace SK.Framework
{public class LanHu : EditorWindow{[MenuItem("SKFramework/Tools/Lan Hu")]private static void Open(){GetWindow<LanHu>("蓝湖").Show();}private const float labelWidth = 60f;private string x;private string y;private string w;private string h;private void OnGUI(){//如果未选中任何物体 returnif (Selection.activeTransform == null) return;RectTransform rt = Selection.activeTransform.GetComponent<RectTransform>();//如果选中的物体不是UI元素 returnif (rt == null) return;GUILayout.Label("分辨率: 1920*1080");EditorGUILayout.Space();GUILayout.Label("样式信息", "BoldLabel");GUILayout.BeginHorizontal();GUILayout.Label("图层", GUILayout.Width(labelWidth));var image = rt.GetComponent<Image>();if (image != null && image.sprite != null) EditorGUILayout.TextField(image.sprite.name);else EditorGUILayout.HelpBox("未发现任何图层", MessageType.Warning);GUILayout.EndHorizontal();GUILayout.BeginHorizontal();GUILayout.Label("位置", GUILayout.Width(labelWidth));x = EditorGUILayout.TextField(x);y = EditorGUILayout.TextField(y);GUILayout.EndHorizontal();GUILayout.BeginHorizontal();GUILayout.Label("大小", GUILayout.Width(labelWidth));w = EditorGUILayout.TextField(w);h = EditorGUILayout.TextField(h);GUILayout.EndHorizontal();GUILayout.FlexibleSpace();if (GUILayout.Button("确定")){float.TryParse(x.Replace(x.Substring(x.Length - 2, 2), string.Empty), out float xValue);float.TryParse(y.Replace(y.Substring(y.Length - 2, 2), string.Empty), out float yValue);float.TryParse(w.Replace(w.Substring(w.Length - 2, 2), string.Empty), out float wValue);float.TryParse(h.Replace(h.Substring(h.Length - 2, 2), string.Empty), out float hValue);//调整位置及大小rt.anchorMin = new Vector2(0, 1);rt.anchorMax = new Vector2(0, 1);rt.pivot = Vector2.one * .5f;rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, wValue);rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, hValue);rt.anchoredPosition = new Vector2(xValue + wValue / 2f, -(yValue + hValue / 2f));//调整完成后自动设置锚点RectTransform prt = rt.parent as RectTransform;Vector2 anchorMin = new Vector2(rt.anchorMin.x + rt.offsetMin.x / prt.rect.width,rt.anchorMin.y + rt.offsetMin.y / prt.rect.height);Vector2 anchorMax = new Vector2(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;EditorUtility.SetDirty(rt);}}private void OnSelectionChange(){Repaint();}}
}

有了上面的工具后,我又开始了这样的思考,如果我们可以直接拿到一个界面中所有图层的样式信息,包括图层名称、位置信息、大小信息,这些信息形成一个Json数据或其他序列化数据文件,那么便可以通过编写工具一键生成这个界面的Prefab预制体。那么我们只需要定义这样一个数据结构,通过数据反序列化得到这些信息:

public class Element
{//图层名称public string name;//横坐标public string x;//纵坐标public string y;//宽度public string width;//高度public string height;//不透明度public string alpha;
}

于是我开始向UI设计的同事咨询,他们从设计到上传蓝湖有没有中间产物生成,能不能从中间产物中获取一些有用的信息,但是同事回应说是通过插件直接从Adobe XD上传至蓝湖,因此这条路便行不通了。但是后来我觉得既然能有上传蓝湖这样的插件,那么编写一个生成数据文件的插件完全有可能吧,只不过没人去做这件事,所以我还是觉得这个想法是行得通的,奈何自己做不来。随后我又从前端着手,咨询了一些朋友,能否在蓝湖页面中获取这些信息,最后也是不了了之。

最终只能在Unity中去着手,将更多的工作量通过自动化去完成,于是又有了这样的思路:记录切图所在的文件夹的路径,从蓝湖中复制粘贴界面中所有图层的样式信息,点击生成,通过图层的名称在切图所在的文件夹中加载该切图,创建一个Image物体,通过图层的位置、大小信息去设置该物体的Rect Transform组件属性,最终生成prefab预制体:  

代码如下:

using System;
using UnityEngine;
using UnityEditor;
using UnityEngine.UI;
using System.Collections.Generic;namespace SK.Framework
{public class LanHu : EditorWindow{[MenuItem("SKFramework/Tools/Lan Hu")]private static void Open(){GetWindow<LanHu>("蓝湖").Show();}private class Element{public string name;public string x;public string y;public string width;public string height;public string alpha;}private string path;private List<Element> elements;private const float labelWidth = 60f;private Vector2 scroll;private void OnEnable(){elements = new List<Element>();scroll = Vector2.zero;}private void OnDisable(){elements.Clear();elements = null;}private void OnGUI(){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();scroll = EditorGUILayout.BeginScrollView(scroll);for (int i = 0; i < elements.Count; i++){var element = elements[i];GUILayout.BeginVertical("Box");GUILayout.BeginHorizontal();GUILayout.Label("图层", GUILayout.Width(labelWidth));element.name = EditorGUILayout.TextField(element.name);if (GUILayout.Button("-", GUILayout.Width(20f))){elements.RemoveAt(i);Repaint();}GUILayout.EndHorizontal();GUILayout.BeginHorizontal();GUILayout.Label("位置", GUILayout.Width(labelWidth));element.x = EditorGUILayout.TextField(element.x);element.y = EditorGUILayout.TextField(element.y);GUILayout.EndHorizontal();GUILayout.BeginHorizontal();GUILayout.Label("大小", GUILayout.Width(labelWidth));element.width = EditorGUILayout.TextField(element.width);element.height = EditorGUILayout.TextField(element.height);GUILayout.EndHorizontal();GUILayout.BeginHorizontal();GUILayout.Label("透明", GUILayout.Width(labelWidth));element.alpha = EditorGUILayout.TextField(element.alpha);GUILayout.EndHorizontal();GUILayout.EndVertical();}EditorGUILayout.EndScrollView();GUILayout.FlexibleSpace();GUILayout.BeginHorizontal();if (GUILayout.Button("添加")){elements.Add(new Element());}if (GUILayout.Button("生成")){//Canvasvar array = path.Split('/');var canvas = new GameObject(array[array.Length - 1]).AddComponent<Canvas>();canvas.renderMode = RenderMode.ScreenSpaceCamera;var canvasScaler = canvas.gameObject.AddComponent<CanvasScaler>();canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;canvasScaler.referenceResolution = new Vector2(1920f, 1080f);for (int i = 0; i < elements.Count; i++){var element = elements[i];string spritePath = path + "/" + element.name + "@2x.png";var obj = AssetDatabase.LoadAssetAtPath<Sprite>(spritePath);if (obj != null){var image = new GameObject(obj.name).AddComponent<Image>();image.transform.SetParent(canvas.transform, false);image.sprite = obj;RectTransform rt = image.transform as RectTransform;float.TryParse(element.x.Replace(element.x.Substring(element.x.Length - 2, 2), string.Empty), out float xValue);float.TryParse(element.y.Replace(element.y.Substring(element.y.Length - 2, 2), string.Empty), out float yValue);float.TryParse(element.width.Replace(element.width.Substring(element.width.Length - 2, 2), string.Empty), out float wValue);float.TryParse(element.height.Replace(element.height.Substring(element.height.Length - 2, 2), string.Empty), out float hValue);//调整位置及大小rt.anchorMin = new Vector2(0, 1);rt.anchorMax = new Vector2(0, 1);rt.pivot = Vector2.one * .5f;rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, wValue);rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, hValue);rt.anchoredPosition = new Vector2(xValue + wValue / 2f, -(yValue + hValue / 2f));//调整完成后自动设置锚点RectTransform prt = rt.parent as RectTransform;Vector2 anchorMin = new Vector2(rt.anchorMin.x + rt.offsetMin.x / prt.rect.width,rt.anchorMin.y + rt.offsetMin.y / prt.rect.height);Vector2 anchorMax = new Vector2(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;}else{Debug.Log($"<color=yellow>加载切图失败 {spritePath}</color>");}}var prefab = PrefabUtility.SaveAsPrefabAsset(canvas.gameObject, $"Assets/{canvas.name}.prefab", out bool result);if (!result){Debug.Log($"<color=yellow>生成预制体失败 {canvas.name}</color>");}else{EditorGUIUtility.PingObject(prefab);}}GUILayout.EndHorizontal();}}
}

Unity 蓝湖 关于UI工作流优化的思考相关推荐

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

    背景和历史版本在下面这篇博客中查看: Unity & 蓝湖 关于UI工作流优化的思考 最新版本: 本文旨在让不会使用Unity的其他人员在简单了解该工具后,可以帮助研发人员搭建Unity中的U ...

  2. 「蓝湖设计协作平台」一切为了更好的交付

    「蓝湖设计协作平台」一切为了更好的交付. 最近,蓝湖对产品性能做了一次整体升级,一句话来说:打开速度更快了,操作更流畅了. 打开速度更快,具体是指设计页和标注页在不同情况下的打开速度均有提升. 比如说 ...

  3. 【愚公系列】2022年10月 微信小程序-电商项目-UI设计之蓝湖的使用

    文章目录 前言 一.UI设计之蓝湖的使用 1.下载插件 2.生成代码 3.配置代码 前言 蓝湖是一款产品文档和设计图的共享平台,帮助互联网团队更好地管理文档和设计图.蓝湖可以在线展示Axure,自动生 ...

  4. 蓝湖ui设计图直接转换html,蓝湖使用规范(用于管理UI及前端切图)

    蓝湖使用规范 一.蓝湖插件下载及安装 二.团队项目建立流程 1.新建团队(横琴人寿) 2.新建项目 在对应的团队下新建项目 例如官微项目,官网项目,i保项目,哆来咪项目 3.新建分组 在相应的项目下按 ...

  5. 蓝湖--UI切图软件,适用于ios,安卓,Web

    蓝湖使用环境,需要在 PSCC2015以上版本使用,需要官方提供的压缩工具才能打开. 官网直接下载安装,结束后可直接在PS,窗口-->扩展工具中打开. 切图及标注使用方法: 扩展中打开,登录蓝湖 ...

  6. 【React组件】写一个模仿蓝湖的图片查看器

    前言 最近公司让写一个可以自由拖拽放大的图片查看器,我寻思这还不简单,一顿操作猛如虎,俩小时后: 事实证明,一旦涉及到 DOM 的变换操作,如果很多细节考虑不全,抓过来就写,那基本就凉了.于是我仔细分 ...

  7. 怎么用class引入svg_【蓝湖指北】走向设计巅峰,从蓝湖 Sketch 插件开始,用它!...

    用好蓝湖,提升团队协作效率,蓝湖指北,教你如何用好蓝湖.本期[蓝湖指北]如约而至- Sketch 作为一款轻量级的矢量设计工具,凭借其强大的界面设计功能,被大多数 UI 设计师所使用,日渐成为产品研发 ...

  8. 蓝湖怎么切图标注_【蓝湖指北】你真的会切图吗?

    ​​用好蓝湖,提升团队协作效率, 蓝湖指北,教你如何用好蓝湖. 本期[蓝湖指北]如约而至- 应付奇葩需求.交付设计图,乃设计师职业生涯中的两大难题.对 UI 设计师而言,交付设计图绝不只是打包.发送设 ...

  9. (51)蓝湖团队协作开发平台

    一.Adobe Photoshop 二.Adobe Fireworks 三.Sketch(Mac版本电脑前端程序员最喜欢的切图工具) 四.插件:Cutterman(早期程序员最爱用的插件) 蓝湖(现在 ...

最新文章

  1. 【Linux迁移到Windows服务器时的注意事项】
  2. CSP认证201612-1 中间数[C++题解]:遍历
  3. WinXP下 扫雷程序逆向分析 --扫雷辅助(一)
  4. Python中collections模块
  5. (王道408考研操作系统)第二章进程管理-第二节4:调度算法详解2(RR、HPF和MFQ)
  6. 写代码也有“套路”-谈谈设计模式
  7. Must 和 have to_54
  8. JVM源码分析之Object.wait/notify(All)完全解读
  9. 32、把数组排成最小的数
  10. Confluence 6 附件存储配置
  11. IOS捷径早安,创建自动化可实现自动化叫醒
  12. 反汇编工具OD(OllyDebug)
  13. SpringBoot项目实现微信小程序登录步骤
  14. html5 答题源码脚本,自动答题脚本教程及源码分享(无视分辨率)
  15. linux两个邮件服务,Linux系列-Red Hat5平台下的Postfix邮件服务搭建(二)
  16. 卷王指南,大学计算机专业,面临分专业,计科,软工,大数据,物联网,网络工程,该选什么?
  17. IP和局域网 简单了解
  18. 2015.3.30第一次博客测试
  19. Nginx学习(四)
  20. IC笔试:​2022小米数字芯片提前批笔试

热门文章

  1. 有人物联网485转网口模块网口调试助手1035未知错误
  2. 字节跳动欢迎你的加入
  3. 将图片以二进制代码形式存入数据库
  4. java微博自动转发_怎样做到让微博用户自动转发你推广的内容?
  5. win10 uwp win2d CanvasVirtualControl 与 CanvasAnimatedControl
  6. 父进程中getpid()值与子进程中getppid()值不相同的问题及解释
  7. 用 Astropy 拟合数据(一)
  8. python自动化操作应用程序错误_python自动化常见问题汇总
  9. Chrome 插件推荐 -- 小米推荐
  10. 练习: 使用Asymptote 画出字母R的轮廓曲线