RectTransform簡析

blueberryzzz發表於2020-09-27

UGUI簡述

  UGUI主要提供了兩個能力

  1. UI元素的渲染與適配(其中UI元素的Mesh中的position資訊就是通過RectTransform生成的,本文重點)
  2. 裝置事件的響應與處理(EventSystem系統,及封裝的Button、Toggle等常用元件)

RectTransform序列化的內容


  也就是說RectTransform是通過這四個屬性來確定RectTransform的四個頂點的(position)。

如何確定頂點資訊

額外屬性的含義

  1. anchorMin:左下角錨點距離父節點左下角的標準距離(父節點所確定四個頂點的矩形的左下角看作(0,0),右上角看作(1,1))。
  2. anchorMax:右上角距離父節點左下角的標準距離。
  3. pivot:中心點距離自身所確定的矩形的左下角的標準距離。
  4. sizeDelta:自身所確定的矩形長寬相對於anchorMin、anchorMax所確定的矩形的偏移量(偏移時會按照pivot的比例來偏移,舉個例子:pivot是(0.3,pY),sizeDelta是(100, sY),那麼自身的矩形左下角會相對於anchorMin負向偏移30,右上角會相對anchorMax正向偏移70,整體將矩形擴大了100。y軸一樣)。
  5. anchoredPosition:自身矩形的中心點相對於anchorMin、anchorMax所確定的矩形中心點的位置(或者也可以理解為偏移量,下面會說)

如何通過這幾個引數來確定自身的矩形

  通過一個例子來說明一個RectTransform的形狀是如何通過上面的幾個引數確定的。
  父節點資訊

  子節點資訊

1.確定anchorMin、anchorMax代表的矩形

  父節點的長寬為(1920,1080),子節點的anchorMin為(0.2,0.3),所以如果把父節點矩形的左下角看作原點,那麼anchorMin所代標的點的座標即為(1920 * 0.2,1080 * 0.3),也就是(384,324)。同理,得到anchorMax代表點的座標(1152,972)。
  也就是一個左下角座標為(384,324),長寬為(1152 - 384,972 - 324),即(768,648)的矩形。
  用RectTransform來表示的話就是下圖這樣,anchorMin、anchorMax、pivot都為(0,0),Pos為(384,324),長寬(768,648)。

2.通過sizeDelta和pivot確定自身矩形的大小

  因為sizeDelta是(100,300),所以接下來對上一步確定的矩形的左下角平移(-100 * 0.4, -300 * 0.5),平移後為(344,174)。右上角的點平移(100 * 0.6, 300 * 0.5),平移後為(1212,1122)。
  用RectTransform來表示的話就是下圖這樣,anchorMin、anchorMax、pivot都為(0,0),Pos為(344,174),長寬(868,948)。

3.通過anchoredPosition對自身進行平移

  把上一步確定的矩形平移子節點的anchoredPositino(60,-200)。
  用RectTransform來表示的話就是下圖這樣,anchorMin、anchorMax、pivot都為(0,0),Pos為(404,-26),長寬(868,948)。
  這個RectTransform所表示的矩形正好可以和子節點的重合,雖然引數不一樣。

注意

  嚴格來說並不是左下角或者右上角,而是指的anchorMin、anchorMax所確定的點。向左、向右指的是父節點空間內的負方向和正方向。但是因為絕大多數情況下anchorMin的xy座標會小於anchorMax的xy座標,這樣才是一個幾何意義明顯的矩形。

RectTransform的Inspector皮膚

  1. 就是anchorsMin、anchorsMax、pivot,上面已經說過了,這理解不說了。
  2. 是就是Transform的localRotaion和localScale屬性,也沒啥好說的。
  3. 這四個數值是對sizeDelta和anchoredPosition的封裝。讓開發者可以更直觀的進行位置和大小的調整。
    具體來說就是左側的兩個值代表了sizeDelta和anchoredPosition的x值,右側的兩個值代表了y值。
    下面就來說一下左邊兩個值的具體含義,當anchorsMin和anchorsMax的x值相等時,也就是這兩個錨點的x座標重合。這個時候這兩個值會變成PosX和Width,其實就是anchoredPosition.x和sizeDelta.x的幾何意義。
    anchoreMin和anchoreMax的x值不等時,也就是這兩個錨點的x座標分離時。會變成left,right。分別代表子節點左側、右側相對於anchoredMin、Max確定的矩形向內的偏移量,十分直觀。其實還是對anchoredPosition.x和sizeDelta.x的封裝。
    右邊的兩個值就對應anchoredPosition.y和sizeDelta.y。
  4. 就是localPosition的z值。在Inspetor中,把localPostion.xy隱藏了,只暴露了z值出來,因為localPositino的xy值一般不會主動去修改,是通過RectorTranform中這幾個額外的屬性動態算出來的。
  5. 一些預設的常用值,縱向代表y,橫向代表x。
  6. 這兩個按鈕是藍圖模式和原始模式,藍圖模式就是在Scene中的那個小框是把RectTranform包起來,還是展示通過這幾個額外屬性確定的矩形(不考慮旋轉和縮放)


    原始模式就是在調整anchors和pivot的時候是否需要動態調整sizeDelta和anchoredPosition來保持該節點的矩形區域不變。選中時代表不動態調整。

localPosition與anchoredPosition的關係

  localPosition就是tranform所確定的座標系原點在父tranform所確定的座標系下的位置。在RectTransform中,自身所確定的座標系原點位置在RectTransform確定的矩形的中心。
  所以在RectTranform下,localPosition也可以理解為自身矩形與父節點確定的矩形中心的相對位置(偏移量)。

localPosition與anchoredPosition的轉換

  先建立以父節點左下角為原點的座標系o。
  定義:
  childPivotPos代表子節點中心點在o中的座標。
  parentPivotPos代表父節點中心點在o中的座標。
  anchorsPivotPos代表子節點anchors確定的矩形的中心點在o中的座標。
  則有:
  localPosition.xy
  = childPivotPos - parentPivotPos
  = (childPivotPos - anchorsPivotPos) + (anchorsPivotPos - parentPivotPos)
  = anchoredPosition + (anchorsPivotPos - parentPivotPos)
  = anchoredPosition + anchorsPivotPos相對於父節點中心的偏移量
  接下來就可以實際上進行計算了。
  定義:
  pSize代表父節點的長寬(除了根Canvas外,其他所有的RectTransform所確定的矩形都是依賴於父節點的。所以我們跳過父節點矩形的計算,直接用rect屬性獲取父節點長寬)。
  pPivot代表父節點的pivot。
  cAnchorsMin、cAnchorsMax、cPivot代表子節點的anchorsMin、anchorsMax、pivot。
  則有:
  parentPivotPos = Vector2.Scale(pSize, pPivot)
  anchorsPivotPos = Vector2.Scale(pSize, cAnchorsMin) + Vector.Scale(pSize, (cAnchorsMax - cAnchorsMin) * cPivot)
  anchorsPivotPos - parentPivotPos = Vector2.Scale(pSize,cAnchorsMin + (cAnchorsMax - cAnchorsMin) * cPivot - pPivot)
  簡單測一下,隨便調調父節點和子節點的屬性。

public class PositionTest : MonoBehaviour
{
    public Vector3 localPosition;
    public Vector2 anchoredPosition;
    public Vector3 delta;
    public Vector3 calculation;

    // Update is called once per frame
    void Update()
    {
        var parentRectTrans = (transform.parent as RectTransform);
        var rectTrans = transform as RectTransform;
        localPosition = rectTrans.localPosition;
        anchoredPosition = rectTrans.anchoredPosition;
        //差值
        delta = (Vector2)localPosition - anchoredPosition;
        //通過公式計算的插值
        calculation = Vector2.Scale(
            parentRectTrans.rect.size,
            rectTrans.anchorMin + (rectTrans.anchorMax - rectTrans.anchorMin) * rectTrans.pivot - parentRectTrans.pivot
        );
    }
}

相關文章