RectTransform详解

示意图

 

1) anchor区域

Vector2 anchorMin;
anchor区域左下角与parent左下角的距离(用parent大小的百分比表示)

Vector2 anchorMax;
anchor区域的右上角与parent右上角的距离(用parent大小的百分比表示)

 

2) 节点坐标: 是相对anchor区域的

Vector2 offsetMin;
节点左下角的坐标(以anchor区域左下角为原点)

Vector2 offsetMax;
节点右上角的坐标(以anchor区域右上角为原点)

 

上面的图中:
offsetMin=(left, bottom)=(40, 30)
offsetMax=(-right, -top)=(-10, -30)

 

3) Vector2 sizeDelta;

节点自身大小与anchor区域大小的差值,计算公式: sizeDelta=offsetMax-offsetMin=rectTransform.rect.size - anchorAreaSize

上面的图中:
sizeDelta=(-10, -30) - (40, 30)=(-50, -60)

 

4) Vector2 anchoredPosition;

计算公式: anchoredPosition = offsetMin + sizeDelta * pivot

一般anchors在横向和竖向都没有设置stretch拉伸时,会用anchoredPosition来设置节点坐标:
因为此时, anchorAreaSize为(0, 0), sizeDelta就是节点自身的大小, anchoredPosition就是pivot的坐标(以anchor区域的pivot为原点)

 

上面的图中: anchoredPosition = (40, 30) + (-50, -60) * (0.4, 0.5) = (20, 0)

根据sizeDelta=offsetMax-offsetMin, 还可以推导出: anchoredPosition = offsetMin + (offsetMax-offsetMin)*pivot = offsetMin*(1-pivot) + offsetMax*pivot

 

5) Rect rect;

rect.position或rect.min: 节点左下角的坐标(以pivot为原点)
rect.center: 中心点坐标(以pivot为原点); 为(0, 0)时, 表示pivot和中心点重合
rect.size: 节点的宽高; anchors设置了stretch也能获取正确的宽高

 

 

节点与parent的边距计算

1) 不考虑节点自身缩放时

left边距 = anchorMin.x * parent宽度 + offsetMin.x = 0.2 * 300 + 40 = 100
bottom边距 = anchorMin.y * parent高度 + offsetMin.y = 0.1 * 200 + 30 = 50
right边距 = (1 - anchorMax.x) * parent宽度 - offsetMax.x = (1 - 0.7) * 300 + 10 = 100
top边距 = (1 - anchorMax.y) * parent高度 - offsetMax.y = (1 - 0.9) * 200 + 30 = 50

 

2) 考虑节点自身缩放

left边距 = anchorMin.x * parent宽度 + offsetMin.x + pivot.x * ((1 - scale.x) * 节点缩放前宽度) = 0.2*300 + 40 + 0.4*((1-0.8)*100) = 108
bottom边距 = anchorMin.y * parent高度 + offsetMin.y + pivot.y * ((1 - scale.y) * 节点缩放前高度) = 0.1*200 + 30 + 0.5*((1-1)*100) = 50
right边距 = (1 - anchorMax.x) * parent宽度 - offsetMax.x + (1 - pivot.x) * ((1 - scale.x) * 节点缩放前宽度) = (1-0.7)*300 + 10 + (1-0.4)*((1-0.8)*100) = 112
top边距 = (1 - anchorMax.y) * parent高度 - offsetMax.y + (1 - pivot.y) * ((1 - scale.y) * 节点缩放前高度) = (1-0.9)*200 + 30 + (1-0.5)((1-1)*100) = 50

 

根据边距设置节点坐标

1) 根据上面的推导,我们自己实现的

public static void SetLocalPosByLeftTopMargin(RectTransform rtf, float leftMargin, float topMargin, Rect parentRect)
{
    var rect = rtf.rect;
    var pivot = rtf.pivot;
    var localScale = rtf.localScale;

    var offsetMin = rtf.offsetMin;
    var offsetMax = rtf.offsetMax;

    var anchorMin = rtf.anchorMin;
    var anchorMax = rtf.anchorMax;

    offsetMin.x = leftMargin - anchorMin.x * parentRect.width - rect.width * pivot.x * (1 - localScale.x);
    offsetMax.x = leftMargin + rect.width - anchorMax.x * parentRect.width;

    offsetMin.y = parentRect.height - topMargin - rect.height - anchorMin.y * parentRect.height;
    offsetMax.y = (1 - anchorMax.y) * parentRect.height + rect.height * (1 - pivot.y) * (1 - localScale.y) - topMargin;

    rtf.offsetMin = offsetMin;
    rtf.offsetMax = offsetMax;
}

 

2) RectTransform上其实也有类似的函数

SetInsetAndSizeFromParentEdge

void Start()
{
    var rtf = GetComponent<RectTransform>();
    var rect = rtf.rect;
    rtf.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, 100, rect.width);
    rtf.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, 50, rect.height);
}

注意:这个函数执行后,会修改anchorMin和anchorMax的值

 

 

参考

Unity3D RectTransform使用详解:布局、属性、方法 - 知乎 (zhihu.com)

 

posted @ 2022-11-26 00:36  yanghui01  阅读(706)  评论(1编辑  收藏  举报