UGUI源碼剖析(3):布局的“原子”——RectTransform的核心數據模型與幾何學

UGUI源碼剖析(第三章):布局的“原子”——RectTransform的核心數據模型與幾何學

在前幾章中,我們了解了UGUI的組件規范和更新調度機制。現在,我們將深入到這個系統的“幾何學”核心,去剖析那個我們每天都在Inspector中調整、但可能從未真正理解其底層原理的組件——RectTransform

RectTransform繼承自標準的Transform,但它并非簡單的擴展,而是一套為二維矩形布局量身定做的、全新的數據模型和坐標系統。理解這個模型,是掌握UGUI布局,并最終明白UI頂點是如何被精確繪制在屏幕上的關鍵。

1. 核心數據模型:一套描述“彈性連接”的語言

要理解RectTransform,我們必須首先拋棄傳統Transform那種“一個點”的思維。RectTransform描述的不是一個點,而是一個矩形,并且這個矩形與它的父矩形之間,是一種**“彈性的、可拉伸的連接關系”**。這五大核心屬性,正是用來定義這種“彈性連接”的語言。

五大核心屬性 (The Core Properties)

1 anchorMin & anchorMax (錨點): 這是整個系統的基石。它們是兩個Vector2值,其坐標是歸一化的(0到1),代表了一個“錨點框”,其位置和尺寸由父RectTransform的尺寸百分比決定。

  • anchorMin: 定義了錨點框的左下角在父矩形中的百分比位置。
  • anchorMax: 定義了錨點框的右上角在父矩形中的百分比位置。

例:底部拉伸
在這里插入圖片描述

  • anchorMin = (0, 0)
  • anchorMax = (1, 0.2)
  • 此時,錨點框是一個橫跨整個父矩形寬度、高度為父矩形20%的矩形區域。

為什么這么設計?
這是RectTransform實現自適應布局核心基石。通過將UI元素的“連接點”定義為父容器尺寸的百分比,而不是固定的像素值,UGUI確保了當父容器(通常是屏幕)尺寸發生變化時,UI元素能夠自動地、按比例地調整自己的位置或尺寸,從而適應不同的分辨率和寬高比。這是一種從“絕對定位”到“相對布局”的思維轉變。

2 pivot (軸心): pivot是一個Vector2值,它的坐標也是歸一化的,但它描述的是RectTransform自身的幾何中心、旋轉中心和縮放中心。(0,0)代表自身的左下角,(0.5, 0.5)代表自身的中心。

pivot將一個矩形的**幾何數據(rect屬性)與其在層級中的變換數據(localPosition等)**分離開來。RectTransform的所有旋轉和縮放操作,都將圍繞pivot點進行。更重要的是,它也是anchoredPosition定位的基準點,我們將在下面看到。

anchoredPosition (錨定位置): 定義了軸心(pivot),相對于錨點框中心像素偏移量

圖例說明:

在這里插入圖片描述

紅色父矩形寬1000,anchorMin = (0.2, 0.5),anchorMax = (0.2, 0.5)
白色子矩形pivot = (0, 0.5)。anchorMin = (0.1, 0.5),anchorMax = (0.1, 0.5)

白色 anchoredPosition.x =400 即是pivot距離錨點框中心400

總寬度度1000*0.1 當前錨點框中心的位置為100,白色矩形軸心正好處在了紅色父矩形的中間位置**(錨點框中心+anchoredPosition.x)(100+400=500)**

3 sizeDelta (尺寸增量): 一個根據錨點模式不同而含義不同的值,我們將在下面深入探討。

4 rect (矩形): 一個只讀屬性,返回了該RectTransform在其本地空間中,以pivot為原點的矩形區域。

2. 模式的奧秘:為什么錨點決定了“拉伸”與否?

在Inspector中,我們常常會注意到,當四個錨點手柄匯聚在一起時,UI的編輯模式會變為Pos X/Y和Width/Height;

而當它們分開時,則會變為Left/Right/Top/Bottom。這種模式切換的背后,正是RectTransform尺寸的核心計算公式在起作用。

一個RectTransform的最終寬度(垂直方向同理)由以下公式決定:

最終寬度 = (anchorMax.x - anchorMin.x) * 父矩形寬度 + sizeDelta.x

這個公式,就是解開所有謎題的鑰匙。

情況A:非拉伸模式 (當 anchorMin == anchorMax)

當anchorMin與anchorMax在某個軸向上相等時,例如anchorMin.x == anchorMax.x,公式中的(anchorMax.x - anchorMin.x)項就等于0

此時,公式簡化為:
最終寬度 = 0 * 父矩形寬度 + sizeDelta.x = sizeDelta.x

技術解讀
在這種情況下,RectTransform的最終寬度完全由sizeDelta.x這一個屬性來決定,它與父矩形的寬度變化完全“脫鉤”。無論父容器如何縮放,它的寬度都將保持不變。因此,我們稱之為**“非拉伸模式”**。Inspector此時顯示Width輸入框,就是讓你直接編輯sizeDelta.x這個值。

情況B:拉伸模式 (當 anchorMin != anchorMax)

當anchorMin與anchorMax在某個軸向上不相等時,(anchorMax.x - anchorMin.x)項不為0

此時,最終寬度的計算公式為:
最終寬度 = (一個不為0的比例) * 父矩形寬度 + sizeDelta.x

技術解讀
在這種情況下,RectTransform的最終寬度是一個與父矩形寬度線性相關的函數。當父矩形寬度變化時,它的寬度也會隨之成比例地“拉伸”或“收縮”。因此,我們稱之為**“拉伸模式”**。sizeDelta.x此時扮演的角色,是在這個“拉伸”的基礎上,再增加或減少一個固定的像素值,像是在一根橡皮筋上增加了一段固定的“延長線”。

3. Inspector的“魔法”:拉伸模式下的邊距編輯

在拉伸模式下,Inspector會智能地隱藏Pos X/Y和Width/Height,轉而顯示Left, Right, Top, Bottom。這套UI的變化,恰恰是為了讓我們能更直觀地操作這種拉伸關系。
在這里插入圖片描述

這四個值,并非RectTransform的核心屬性,而是Unity編輯器為我們提供的“便利接口”。它們實際上是在間接地、協同地修改anchoredPosition和sizeDelta這兩個核心屬性。

它們到底代表什么?
在拉伸模式下,Left, Right, Top, Bottom定義了RectTransform的四個邊界,相對于其對應的四個錨點像素距離(或稱為邊距/Margin)。

舉例說明:
在這里插入圖片描述

  • 場景設定
    • 父矩形寬度為 1000
    • 子RectTransform的錨點設置為左右拉伸:anchorMin.x = 0.1 (父級左邊10%),anchorMax.x = 0.9 (父級右邊90%)。
    • 此時,左錨點在世界坐標的100處,右錨點在900處。
  • 你在Inspector中輸入:Left = 20, Right = 30
    • 背后發生的事:Unity會進行一系列復雜的反向計算,最終設定好anchoredPosition.x和sizeDelta.x的值,以確保一個結果:
      • RectTransform的左邊界,會位于其左錨點(100處)向右20的位置,即120處。
      • RectTransform的右邊界,會位于其右錨點(900處)向左30的位置,即870處。
    • 當你只修改Left的值,比如增加它,你會看到UI的左邊界向右移動,而右邊界保持不變,UI變窄。

這套UI,將背后復雜的數學聯動,抽象成了一套非常直觀的、**“調整邊距”**的操作模式,這正是Unity編輯器設計的精妙之處。

4. 從布局到幾何:OnPopulateMesh的最終轉換

現在,我們帶著對RectTransform數據模型和其編輯模式的深刻理解,來審視最終的一步:Graphic組件是如何利用這些布局數據,來生成最終要渲染的Mesh的。

Graphic基類的OnPopulateMesh默認實現,為我們揭示了這個轉換過程:

protected virtual void OnPopulateMesh(VertexHelper vh)
{var r = GetPixelAdjustedRect();var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height);// ... 用v來生成四個頂點 ...
}

技術解讀

  1. 獲取最終矩形 (GetPixelAdjustedRect()): Graphic并不直接使用rectTransform.rect,而是調用GetPixelAdjustedRect()。這個方法會考慮Canvas的pixelPerfect(像素完美)設置,對rectTransform.rect的結果進行微調,使其邊緣對齊到最近的物理像素,以避免模糊。
  2. RectTransform.rect的幾何意義: rectTransform.rect這個至關重要的只讀屬性,返回的是RectTransform的本地矩形。這個矩形的尺寸,是由sizeDelta和錨點共同決定的;而它的坐標系原點(0,0),就是pivot(軸心)所在的位置
    • 例如,一個100x100的矩形,如果pivot在中心(0.5, 0.5),那么rect就是{x:-50, y:-50, width:100, height:100}。它的四個角的本地坐標就是(-50,-50), (-50,50), (50,50)和(50,-50)。
  3. 生成頂點: OnPopulateMesh方法中,正是利用了這個以軸心為原點的本地矩形r,來生成四個頂點的。這四個頂點的position,就是RectTransform本地空間(local space)中的四個角的坐標。這個過程,就完成了從RectTransform的抽象布局數據,到Mesh的具體幾何數據的最終轉換。這些本地空間的頂點,在后續的渲染流程中,會通過transform.localToWorldMatrix被轉換到世界空間,并最終顯示在屏幕上。

總結:

RectTransform是UGUI布局系統的“原子單位”。它通過一套精巧的、基于“錨點”的核心數據模型,在“非拉伸”和“拉伸”兩種模式下,統一地定義了UI元素在二維空間中的尺寸和相對位置。Unity編輯器則通過一系列智能的“幕后”補償算法和動態的UI切換,極大地優化了我們對這套復雜模型的編輯體驗。

最終,這套布局數據在Graphic的OnPopulateMesh方法中,被“降維”和“固化”為一組相對于自身軸心的、具體的本地空間頂點坐標。正是這個從**“相對布局描述”“絕對幾何坐標”**的關鍵轉換,構成了UGUI能夠將靈活的布局系統,與Unity底層渲染管線無縫對接的橋梁。

理解RectTransform從“彈性連接”到“原始頂點”的完整生命周期,是所有UGUI高級布局技術和性能優化的基礎。只有掌握了這個“原子”的規律,我們才能在更宏觀的層面,去構建穩定、高效、可自適應的復雜UI。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/918363.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/918363.shtml
英文地址,請注明出處:http://en.pswp.cn/news/918363.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

c++注意點(15)----設計模式(橋接模式與適配器模式)

一、結構型設計模式兩者有點相似,都是為了做到解耦的功能。適配器模式是一種結構型設計模式, 它能使接口不兼容的對象能夠相互合作。橋接模式是一種結構型設計模式, 可將一個大類或一系列緊密相關的類拆分為抽象和實現兩個獨立的層次結構&…

DuoPlus支持導入文件批量配置云手機參數,還優化了批量操作和搜索功能!

作為我常用的一款還不錯的跨境工具,DuoPlus云手機幫我高效完成了很多跨境工作,它的功能也在逐步完善和優化,今天來聊聊它最近新更新的一些功能。功能更新一覽新增導入文件配置參數:批量初始化代理、批量修改參數支持導入文件一鍵配…

PLC如何實現通過MQTT協議物聯網網關接入管理云平臺

在工業4.0與智能制造浪潮下,企業亟需實現設備數據的高效采集與云端協同,以支撐遠程監控、預測性維護等場景。工業智能網關憑借其強大的協議解析能力、邊緣計算功能及安全傳輸機制,成為PLC接入云平臺的核心解決方案。本文將從技術架構、功能模…

通過sealos工具在ubuntu 24.02上安裝k8s集群

一、系統準備(1)安裝openssh服務 sudo apt install openssh-server sudo systemctl start ssh sudo systemctl enable ssh(2)放通防火墻 sudo ufw allow ssh(3)開通root直接登錄 vim /etc/ssh/sshd_config#…

nginx+Lua環境集成、nginx+Lua應用

nginxluaredis實踐 概述 nginx、lua訪問redis的三種方式: 1。 HttpRedis模塊。 指令少,功能單一 ,適合簡單的緩存。只支持get 、select命令。 2。 HttpRedis2Module模塊。 功能強大,比較靈活。 3。 lua-resty-redis庫 OpenResty。…

機器學習 K-Means聚類 無監督學習

目錄 K-Means 聚類:從原理到實踐的完整指南 什么是 K-Means 聚類? 應用場景舉例 K-Means 算法的核心原理 K-Means 算法的步驟詳解 可視化理解 K-Means 的優缺點分析 優點 缺點 如何選擇合適的 K 值? 1. 肘部法(Elbow Me…

RabbitMQ面試精講 Day 16:生產者優化策略與實踐

【RabbitMQ面試精講 Day 16】生產者優化策略與實踐 開篇 歡迎來到"RabbitMQ面試精講"系列第16天,今天我們聚焦RabbitMQ生產者優化策略與實踐。在消息隊列系統中,生產者的性能表現直接影響整個系統的吞吐量和可靠性。掌握生產者優化技巧不僅能…

Android 系統的安全 和 三星安全的區別

維度Android(AOSP 通用)Samsung(Knox 強化)本質差異一句話信任根標準 Verified Boot(公鑰由谷歌或 OEM 托管)額外在 自家 SoC 里燒錄 Knox 密鑰 熔絲位,一旦解鎖即觸發 Knox 0x1 熔斷&#xff…

開源大模型實戰:GPT-OSS本地部署與全面測評

文章目錄一、引言二、安裝Ollama三、Linux部署GPT-OSS-20B模型四、模型測試4.1 AI幻覺檢測題題目1:虛假歷史事件題目2:不存在的科學概念題目3:虛構的地理信息題目4:錯誤的數學常識題目5:虛假的生物學事實4.2 算法題測試…

【無標題】命名管道(Named Pipe)是一種在操作系統中用于**進程間通信(IPC)** 的機制

命名管道(Named Pipe)是一種在操作系統中用于進程間通信(IPC) 的機制,它允許不相關的進程(甚至不同用戶的進程)通過一個可見的文件系統路徑進行數據交換。與匿名管道(僅存在于內存&a…

Baumer相機如何通過YoloV8深度學習模型實現危險區域人員的實時檢測識別(C#代碼UI界面版)

《------往期經典推薦------》 AI應用軟件開發實戰專欄【鏈接】 序號 項目名稱 項目名稱 1 1.工業相機 + YOLOv8 實現人物檢測識別:(C#代碼,UI界面版) 2.工業相機 + YOLOv8 實現PCB的缺陷檢測:(C#代碼,UI界面版) 2 3.工業相機 + YOLOv8 實現動物分類識別:(C#代碼,U…

本文章分享一個本地錄音和實時傳輸錄音給app的功能(杰理)

我用的是杰理手表sdk,該功能學會就可自行在任何杰里sdk上做,庫函數大致一樣,學會運用這個方向就好。1.我們要驗證這個喇叭和麥是否正常最簡單的的辦法,就是直接萬用表測試,直接接正負極,看看是否通路&#…

Netty-Rest搭建筆記

0.相關知識Component、Repository、ServiceRepository //Scope設置bean的作用范圍 Scope("singleton")//單例 prototype每次創建都會給一個新實例。 public class BookDaoImpl implements BookDao { //生命周期public void save() {System.out.println("book d…

工作筆記-----lwip網絡任務初始化問題排查

工作筆記-----基于FreeRTOS的lwIP網絡任務初始化問題排查 Author:明月清了個風Date: 2025/8/10PS:新項目中在STMF7開發板上基于freeRTOS和lwIP開發網口相關任務,開發過程中遇到了網口無法連接的問題,進行了一系列的排查…

Kotlin動態代理池+無頭瀏覽器協程化實戰

我看到了很多作者展示了Kotlin在爬蟲領域的各種高級用法。我需要從中提取出最"牛叉"的操作,也就是那些充分利用Kotlin語言特性,使爬蟲開發更高效、更強大的技巧。 我準備用幾個主要部分來組織內容,每個部分會突出Kotlin特有的"…

PDF編輯工具,免費OCR識別表單

軟件介紹 今天推薦一款功能全面的PDF編輯工具——PDF XChange Editor,支持文本、圖片編輯及OCR識別,還能一鍵提取表單信息,滿足多樣化PDF處理需求。 軟件優勢 該軟件完全免費,下載后雙擊圖標即可直接運行,無需安裝&…

OpenEnler等Linux系統中安裝git工具的方法

在歐拉系統中安裝 Git使用 yum 包管理器安裝(推薦,適用于歐拉等基于 RPM 的系統):# 切換到 root 用戶(若當前不是) su - root# 安裝 Git yum install -y git驗證安裝是否成功:git --version若輸…

UE5 第三人稱視角如何設置camera移動旋轉

“奇怪,這blog不支持md格式嗎”## 第1步:設置玩家Pawn 創建一個藍圖類,繼承自 Pawn,在游戲模式(Game Mode)中,將這個Pawn設置為默認 在組件面板中,添加一個 Spring Arm 組件 在組件面…

OpenCV 入門教程:開啟計算機視覺之旅

目錄 一、引言? 二、OpenCV 簡介 ?(一)什么是 OpenCV (二)OpenCV 的特點與優勢 (三)OpenCV 的應用領域 三、環境搭建 (一)安裝 OpenCV 庫? 四、OpenCV 基礎操作 &#xf…

C++高頻知識點(十九)

文章目錄91. TCP斷開連接的時候為什么必須4次而不是3次?92. 為什么要區分用戶態和內核態?93. 說說編寫socket套接字的步驟1. 服務器端編寫步驟1.1 創建套接字1.2 綁定套接字1.3 監聽連接1.4 接受連接1.5 數據傳輸1.6 關閉套接字2. 客戶端編寫步驟2.1 創建…