本随笔参考了以下博客,在此基础上进行优化和改进:
https://blog.csdn.net/qq_39640124/article/details/88284191
ugui中的Anchor预设如下:
允许我们快速对齐父物体的一部分轴向顶点或边,但有时我们并不是要对齐这些,而是需要对齐特定位置的某个点,例如:
如上图,上面的作战结束之后的等级信息B它应该是对齐父物体面板的什么位置呢?
当然了,你可以简单的将它设置为对齐屏幕右侧中点或者右上,那么此时无论屏幕分辨率如何改变,它的锚点Pivot距离屏幕右边缘的距离都不变。
但如果出现一种极端例子,屏幕的宽度小到比预设的距离还小,那么B早就跑到屏幕左侧去了。
显然,这样的Anchor预设调整是不太精准的,在屏幕分辨率改变较大时,很多不同对齐方式的元素有极大几率出现位置偏移甚至重叠。
ugui除了通过自带的预设,也可以手动输入Anchor的最大值和最小值来调整,当最大值和最小值相同时,它对齐的是相对百分比的一个点:
例如上面的B字母的中点精准的对齐方式是,距离父物体画布宽的82.9%高72.7%左右的位置,这样无论父物体随着分辨率如何改变,B的相对位置都保持不变。
值得注意的是,为了保证无任何偏移的可能,需要保证anchoredPosition为零,也就是面板中Pos为零。
但很遗憾的是,Unity编辑器暂时还没有办法自动对齐Anchor到物体的锚点Pivot或边框,当然了你可以每次尝试手动拖动,但保证你马上就会有口区的感觉,而且总会差那么一点对不齐。
下面是自动对齐的编辑器脚本,在网上参考了之前网友写过的对齐边框的写法,但发现只要锚点Pivot不在物件中心就会自动移动物体位置,在这里进行了一些优化修正,并增加了另一种对齐模式:
1 using UnityEngine; 2 using UnityEditor; 3 4 public class AnchorsAdapt 5 { 6 [MenuItem("Tools/AnchorsAdaptSize")] 7 private static void SelectionMS() 8 { 9 GameObject[] gos = Selection.gameObjects; 10 for (int i = 0; i < gos.Length; i++) 11 { 12 if (gos[i].GetComponent<RectTransform>() == null) 13 continue; 14 AdaptSize(gos[i]); 15 } 16 } 17 18 [MenuItem("Tools/AnchorsAdaptPivot")] 19 private static void SelectionMP() 20 { 21 GameObject[] gos = Selection.gameObjects; 22 for (int i = 0; i < gos.Length; i++) 23 { 24 if (gos[i].GetComponent<RectTransform>() == null) 25 continue; 26 AdaptPivot(gos[i]); 27 } 28 } 29 30 private static void AdaptPivot(GameObject go) 31 { 32 //------获取rectTransform---- 33 RectTransform partentRect = go.transform.parent.GetComponent<RectTransform>(); 34 RectTransform localRect = go.GetComponent<RectTransform>(); 35 36 //位置信息 37 Vector3 partentPos = go.transform.parent.position; 38 Vector3 localPos = go.transform.position; 39 40 float partentWidth = partentRect.rect.width; 41 float partentHeight = partentRect.rect.height; 42 43 //---------位移差------ 44 float offX = localPos.x - partentPos.x; 45 float offY = localPos.y - partentPos.y; 46 47 float rateW = offX / partentWidth; 48 float rateH = offY / partentHeight; 49 var anchor = new Vector2(.5f + rateW, .5f + rateH); 50 localRect.SetRtAnchorSafe(anchor, anchor); 51 } 52 53 private static void AdaptSize(GameObject go) 54 { 55 //位置信息 56 Vector3 partentPos = go.transform.parent.position; 57 Vector3 localPos = go.transform.position; 58 //------获取rectTransform---- 59 RectTransform partentRect = go.transform.parent.GetComponent<RectTransform>(); 60 RectTransform localRect = go.GetComponent<RectTransform>(); 61 62 float partentWidth = partentRect.rect.width; 63 float partentHeight = partentRect.rect.height; 64 float localWidth = localRect.rect.width * 0.5f; 65 float localHeight = localRect.rect.height * 0.5f; 66 //---------位移差------ 67 float offX = localPos.x - partentPos.x; 68 float offY = localPos.y - partentPos.y; 69 70 float rateW = offX / partentWidth; 71 float rateH = offY / partentHeight; 72 localRect.anchorMax = localRect.anchorMin = new Vector2(0.5f + rateW, 0.5f + rateH); 73 localRect.anchoredPosition = Vector2.zero; 74 75 //大小偏移 76 partentHeight = partentHeight * 0.5f; 77 partentWidth = partentWidth * 0.5f; 78 float rateX = (localWidth / partentWidth) * 0.5f; 79 float rateY = (localHeight / partentHeight) * 0.5f; 80 81 //锚点偏移值 82 var pivotOffX = localRect.pivot.x-.5f; 83 var pivotOffY = localRect.pivot.y-.5f; 84 var pivotOff = new Vector2(localWidth * pivotOffX / partentWidth, localHeight * pivotOffY / partentHeight); 85 86 localRect.anchorMax = new Vector2(localRect.anchorMax.x + rateX, localRect.anchorMax.y + rateY) - pivotOff; 87 localRect.anchorMin = new Vector2(localRect.anchorMin.x - rateX, localRect.anchorMin.y - rateY) - pivotOff; 88 localRect.offsetMax = localRect.offsetMin = Vector2.zero; 89 } 90 }
此脚本为编辑器Editor脚本,需要放在Editor文件夹下才能生效。其中安全设置Anchor的拓展方法如下:
1 public static void SetRtAnchorSafe(this RectTransform rt, Vector2 anchorMin, Vector2 anchorMax) 2 { 3 if (anchorMin.x < 0 || anchorMin.x > 1 || anchorMin.y < 0 || anchorMin.y > 1 || anchorMax.x < 0 || anchorMax.x > 1 || anchorMax.y < 0 || anchorMax.y > 1) 4 return; 5 6 var lp = rt.localPosition; 7 //注意不要直接用sizeDelta因为该值会随着anchor改变而改变 8 var ls = new Vector2(rt.rect.width, rt.rect.height); 9 10 rt.anchorMin = anchorMin; 11 rt.anchorMax = anchorMax; 12 13 //动态改变anchor后size和localPostion可能会发生变化需要重新设置 14 rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, ls.x); 15 rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, ls.y); 16 rt.localPosition = lp; 17 }