前言 上半年的大半年时间都在用FGUI,最近又用回了UGUI,发现FGUI的一些工具还是很高效的,比如对齐工具,想着说移植到UGUI里面去,上网搜了一圈还真有,原理并不复杂,就是进行一些数学计算出最终的位置。
不过也没有完全适合项目需求,针对原项目基础上添加了三个功能,下面介绍一下。
一、撤销功能 原项目的工具在修改后,习惯性就按下Ctrl+Z,发现并不能撤销原来的操作,查询了Unity的API后,发现有个Undo的类,可以实现撤销功能,有很多方法,主要用到了RecordObject,代码如下
private static void SetTranPos(Transform tran, Vector3 pos) { Undo.RecordObject(tran, "modify posstion"); tran.position = pos; } 二、Selection.GameObjects不是按选择顺序的 API中的Selection.GameObjects用于获取当前选中的物件,数组的顺序和我选择的顺序无关,所以不能实现灵活的对齐,查询网上文章可以用Selection.Objects替代,里面的第一个元素就是Ctrl选中的第一个元素,以此类推,代码如下
//按选中顺序获取GameObjects private static GameObject[] GetOrderedSelctionObjs() { return Selection.objects.OfType<GameObject>().ToArray(); } 三、添加对父节点对齐 功能就是和标题一样,原项目是没有的,代码如下
//如果只选中一个,对父节点对齐 if (rects.Count == 1) { if (rects[0].parent != null && rects[0].parent.GetComponent<RectTransform>() != null) { rects.Insert(0, rects[0].parent.GetComponent<RectTransform>()); } } 四、代码 UGUIAlign using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; public enum AlignType { Top = 1, Left = 2, Right = 3, Bottom = 4, HorizontalCenter = 5, //水平居中 VerticalCenter = 6, //垂直居中 Horizontal = 7, //横向分布 Vertical = 8, //纵向分布 } public class UGUIAlign : Editor { [MenuItem("GameObject/UI/Align/Left 【左对齐】")] static void AlignLeft() { Align(AlignType.Left); } [MenuItem("GameObject/UI/Align/HorizontalCenter 【水平居中】")] static void AlignHorizontalCenter() { Align(AlignType.HorizontalCenter); } [MenuItem("GameObject/UI/Align/Right 【右对齐】")] static void AlignRight() { Align(AlignType.Right); } [MenuItem("GameObject/UI/Align/Top 【顶端对齐】")] static void AlignTop() { Align(AlignType.Top); } [MenuItem("GameObject/UI/Align/VerticalCenter 【垂直居中】")] static void AlignVerticalCenter() { Align(AlignType.VerticalCenter); } [MenuItem("GameObject/UI/Align/Bottom 【底端对齐】")] static void AlignBottom() { Align(AlignType.Bottom); } [MenuItem("GameObject/UI/Align/Horizontal 【横向分布】")] static void AlignHorizontal() { Align(AlignType.Horizontal); } [MenuItem("GameObject/UI/Align/Vertical 【纵向分布】")] static void AlignVertical() { Align(AlignType.Vertical); } public static void Align(AlignType type) { List<RectTransform> rects = new List<RectTransform>(); GameObject[] objects = GetOrderedSelctionObjs(); if (objects != null && objects.Length > 0) { for (int i = 0; i < objects.Length; i++) { RectTransform rect = objects[i].GetComponent<RectTransform>(); if (rect != null) rects.Add(rect); } } //如果只选中一个,对父节点对齐 if (rects.Count == 1) { if (rects[0].parent != null && rects[0].parent.GetComponent<RectTransform>() != null) { rects.Insert(0, rects[0].parent.GetComponent<RectTransform>()); } } if (rects.Count > 1) { Align(type, rects); } } //按选中顺序获取GameObjects private static GameObject[] GetOrderedSelctionObjs() { return Selection.objects.OfType<GameObject>().ToArray(); } public static void Align(AlignType type, List<RectTransform> rects) { RectTransform tenplate = rects[0]; float w = tenplate.sizeDelta.x * tenplate.lossyScale.x; float h = tenplate.sizeDelta.y * tenplate.lossyScale.y; float x = tenplate.position.x - tenplate.pivot.x * w; float y = tenplate.position.y - tenplate.pivot.y * h; switch (type) { case AlignType.Top: for (int i = 1; i < rects.Count; i++) { RectTransform trans = rects[i]; float th = trans.sizeDelta.y * trans.lossyScale.y; Vector3 pos = trans.position; pos.y = y + h - th + trans.pivot.y * th; SetTranPos(trans, pos); } break; case AlignType.Left: for (int i = 1; i < rects.Count; i++) { RectTransform trans = rects[i]; float tw = trans.sizeDelta.x * trans.lossyScale.x; Vector3 pos = trans.position; pos.x = x + tw * trans.pivot.x; SetTranPos(trans, pos); } break; case AlignType.Right: for (int i = 1; i < rects.Count; i++) { RectTransform trans = rects[i]; float tw = trans.sizeDelta.x * trans.lossyScale.x; Vector3 pos = trans.position; pos.x = x + w - tw + tw * trans.pivot.x; SetTranPos(trans, pos); } break; case AlignType.Bottom: for (int i = 1; i < rects.Count; i++) { RectTransform trans = rects[i]; float th = trans.sizeDelta.y * trans.lossyScale.y; Vector3 pos = trans.position; pos.y = y + th * trans.pivot.y; SetTranPos(trans, pos); } break; case AlignType.HorizontalCenter: for (int i = 1; i < rects.Count; i++) { RectTransform trans = rects[i]; float tw = trans.sizeDelta.x * trans.lossyScale.x; Vector3 pos = trans.position; pos.x = x + 0.5f * w - 0.5f * tw + tw * trans.pivot.x; SetTranPos(trans, pos); } break; case AlignType.VerticalCenter: for (int i = 1; i < rects.Count; i++) { RectTransform trans = rects[i]; float th = trans.sizeDelta.y * trans.lossyScale.y; Vector3 pos = trans.position; pos.y = y + 0.5f * h - 0.5f * th + th * trans.pivot.y; SetTranPos(trans, pos); } break; case AlignType.Horizontal: float minX = GetMinX(rects); float maxX = GetMaxX(rects); rects.Sort(SortListRectTransformByX); float distance = (maxX - minX) / (rects.Count - 1); for (int i = 1; i < rects.Count - 1; i++) { RectTransform trans = rects[i]; Vector3 pos = trans.position; pos.x = minX + i * distance; SetTranPos(trans, pos); } break; case AlignType.Vertical: float minY = GetMinY(rects); float maxY = GetMaxY(rects); rects.Sort(SortListRectTransformByY); float distanceY = (maxY - minY) / (rects.Count - 1); for (int i = 1; i < rects.Count - 1; i++) { RectTransform trans = rects[i]; Vector3 pos = trans.position; pos.y = minY + i * distanceY; SetTranPos(trans, pos); } break; } } private static void SetTranPos(Transform tran, Vector3 pos) { Undo.RecordObject(tran, "modify posstion"); tran.position = pos; } private static int SortListRectTransformByX(RectTransform r1, RectTransform r2) { float w = r1.sizeDelta.x * r1.lossyScale.x; float x1 = r1.position.x - r1.pivot.x * w; w = r2.sizeDelta.x * r2.lossyScale.x; float x2 = r2.position.x - r2.pivot.x * w; if (x1 >= x2) return 1; else return -1; } private static int SortListRectTransformByY(RectTransform r1, RectTransform r2) { float w = r1.sizeDelta.y * r1.lossyScale.y; float y1 = r1.position.y - r1.pivot.y * w; w = r2.sizeDelta.y * r2.lossyScale.y; float y2 = r2.position.y - r2.pivot.y * w; if (y1 >= y2) return 1; else return -1; } private static float GetMinX(List<RectTransform> rects) { if (null == rects || rects.Count == 0) return 0; RectTransform tenplate = rects[0]; float minx = tenplate.position.x; float tempX = 0; for (int i = 1; i < rects.Count; i++) { tempX = rects[i].position.x; if (tempX < minx) minx = tempX; } return minx; } private static float GetMaxX(List<RectTransform> rects) { if (null == rects || rects.Count == 0) return 0; RectTransform tenplate = rects[0]; float maxX = tenplate.position.x; float tempX = 0; for (int i = 1; i < rects.Count; i++) { tempX = rects[i].position.x; if (tempX > maxX) maxX = tempX; } return maxX; } private static float GetMinY(List<RectTransform> rects) { if (null == rects || rects.Count == 0) return 0; RectTransform tenplate = rects[0]; float minY = tenplate.position.y; float tempX = 0; for (int i = 1; i < rects.Count; i++) { tempX = rects[i].position.y; if (tempX < minY) minY = tempX; } return minY; } private static float GetMaxY(List<RectTransform> rects) { if (null == rects || rects.Count == 0) return 0; RectTransform tenplate = rects[0]; float maxY = tenplate.position.y; float tempX = 0; for (int i = 1; i < rects.Count; i++) { tempX = rects[i].position.y; if (tempX > maxY) maxY = tempX; } return maxY; } } 五、代码下载 https://github.com/dandkong/UGUIAlign
...