Unity ugui Anchor錨點自動適配畫布中的相對位置

本隨筆參考了以下部落格,在此基礎上進行優化和改進:

//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     }