RectTransform
Unity UI 系統使用 RectTransform 實作基本的布局和層次控制。
RectTransform 繼承于 Transform。是以 Transform 的全部特征 RectTransform 同樣擁有。
在 Transform 基礎上,RectTransform 添加了 軸心(pivot)、錨點(實際上是用 anchorMin、anchorMax 兩個點定義的矩形區域)、和 尺寸變化量(sizeDelta)。
軸心:表示UI元素的中心,使用相對于自身矩形範圍的百分比表示的點位置。這會影響定位、縮放和旋轉。
錨點:相對于父級矩形的子矩形區域。這個矩形各個邊界值使用百分比表示。
尺寸變化量:相對錨點定義的子矩形的大小變化量,與錨點定義的子矩形合并後的區域才是最終的UI矩形。
在 Inspector 界面上,為了更友善的調節 RectTransform 的屬性,錨點的兩個點重合時會顯示位置和寬高(直接調節位置和sizeDelta)。否則顯示相對錨點矩形邊界的偏移量(通過計算後再指派給位置和sizeDelta)。在程式中。RectTransform 加入了 anchoredPosition 和 rect 屬性來更友善的程式設計。
RectTransform 元件同樣負責組織 GameObject 的層級關系。
在 UI 系統中,子級 UI 對象總是覆寫顯示在父級 UI 對象上。層級同樣的 UI 對象,下方的 UI 對象總是覆寫顯示在上方的 UI 對象上。這種設計避免了繁瑣的深度設定。在程式中。Transform 加入了 SetSiblingIndex、GetSiblingIndex、SetAsFirstSibling、SetAsLastSibling 這些方法來友善的改動物體的層級順序。
EventSystem
假設你使用 UI 系統,那麼 EventSystem 對象會自己主動建立。這個對象負責監聽使用者輸入。預設情況下,在電腦上能夠使用鍵盤和滑鼠輸入,在移動裝置上能夠使用觸摸輸入。可是假設你要為surface這種裝置開發,你也能夠同一時候啟用兩種輸入。
當須要屏蔽使用者輸入時,将此對象關閉就可以。UnityEngine.EventSystems.EventSystem.current 儲存了目前活動的 EventSystem 對象。
Canvas
Canvas 是其它全部 UI 對象的根。在一個場景裡 Canvas 數量和層級都沒有限制。
子 Canvas 使用與父 Canvas 同樣的渲染模式。
一個 Canvas 有三種渲染模式:
Screen Space - Overlay:UI元素相對于螢幕空間,以2D方式顯示在不論什麼相機畫面的上面。這是很标準的 UI 風格。典型樣例:大量窗體、文本和button的政策遊戲。
Screen Space - Camera:UI元素相對于螢幕空間,由指定的相機負責顯示,相機的參數影響顯示的結果。你能夠把 Canvas 了解為相機的子物體。
典型樣例:射擊遊戲螢幕上的 3D HUD。
World Space:UI元素相對于世界空間。和其它場景裡的物體一樣有世界位置、遮擋關系。通經常使用來做很創新的 UI 設計。
樣例:遊戲内的手機螢幕、與場景綁定的遊戲指導等。
CanvasScaler
這個元件負責螢幕适配。UI 系統使用 RectTransform 來計算 UI 的位置和大小。但這還不夠。怎樣讓設計的 UI 能夠适配不同的分辨率、寬高比和 DPI?這個元件給出了以下3種适配方法。注意不論什麼一種适配方法都不會改變UI的寬高比和相對定位。
Constant Pixel Size:通過調節 Canvas 像素大小來維持縮放不變。它的意思是在不論什麼螢幕上不改變 Canvas 的縮放系數(Scale Factor),而是調節 Canvas 的像素大小與螢幕保持一緻。你能夠手動或通過代碼調節 Canvas 的縮放系數。這是 UI 系統預設的适配方案。例如以下圖兩種分辨率下同樣的UI顯示的不同之處,盡管不同螢幕下UI元素定位、大小沒有發生變化(圖中兩個白色元素定位分别為螢幕左上角和右下角)。可是較小的螢幕上UI元素占用了大部分螢幕空間。顯得更擁擠。
這就是這種适配方式的缺點。小螢幕太擁擠、大螢幕太空曠,沒有考慮到螢幕的分辨率和DPI。可是這種模式的優點是UI元素能夠保持設計時的細節(由于沒有縮放)。這種模式可能适用于:你希望UI在一定範圍内按原始大小顯示。這樣既能夠讓UI顯示的盡可能清晰、又能夠讓螢幕較大的玩家擁有更廣闊的視野,可是在太小或太大的螢幕上,你能夠通過程式來調節縮放系數。不至于小螢幕被UI占滿、大螢幕找不到UI。
Scale With Screen Size:依據螢幕分辨率縮放。這可能是大部分遊戲最友善的适配方法。
在這種模式下。你須要指定一種設計分辨率,然後指定縮放的算法。不管哪種縮放算法,假設實際寬高比與設計寬高比同樣。UI 都會被等比縮放。實際上。Canvas 僅僅是保持自己的大小和設計分辨率一緻。假設實際寬高比與設計寬高比不同,這時縮放算法才會影響顯示結果。縮放算法有三種:擴充、收縮 和 比對寬高。
擴充算法的邏輯是,擴大 Canvas (在寬高比上)較短的一邊。使得 Canvas 寬高比與螢幕一緻。
例如以下左圖。設計分辨率寬高比為1:1(紅色線框)。實際螢幕更寬是以 Canvas 的 width 添加以比對螢幕。
這種算法在寬高比不同的螢幕上将始終導緻UI更“開闊”。收縮算法的邏輯是,收縮 Canvas (在寬高比上)較長的一邊,使得 Canvas 寬高比與螢幕一緻。例如以下中圖,設計分辨率寬高比為1:1(紅色線框),實際螢幕更窄是以 Canvas 的 height 減小以比對螢幕。這種算法在寬高比不同的螢幕上将始終導緻UI更“緊湊”。
比對寬高的算法邏輯是,依據指定的權重,同一時候調節 Canvas 的寬和高。使得 Canvas 寬高比與螢幕一緻。例如以下右圖。設計分辨率為紅色線框。設定寬度和高度的權重相等(0.5)。實際螢幕上 Canvas 的寬和高都被調整以比對螢幕。這種算法目的是,通過可調節的寬高權重,盡可能的保持UI的原始設計。
Constant Physical Size:通過調節 Canvas 實體大小來維持縮放不變。它的意思是在不論什麼螢幕上不改變 Canvas 的 DPI,而是調節 Canvas 的實體大小總是與螢幕保持一緻。
這種說法可能比 Constant Pixel Size 更難以了解,實際上他們本質是一樣的,僅僅隻是 Constant Pixel Size 通過邏輯像素大小調節來維持縮放。而 Constant Physical Size 通過實體大小調節來維持縮放。使用這種模式必須指定一個像素轉換實體大小的因數(填寫96友善在windows上進行開發)。執行時通過詳細裝置報告的dpi計算 Canvas 像素大小和縮放系數。
這種模式從設計的意圖來看,是為了在開發時使用實體機關而非像素機關。這僅僅會讓程式和美術的工作變得複雜,實際使用價值并不高。由于開發者更關心設計的像素分辨率。他們須要繪制明白的像素大小的圖檔。假設未來開發者和玩家都使用了超高DPI的顯示器。那時也許會更注重實體尺寸。
Selectable
可互動UI元件的基類。它負責響應使用者的輸入,産生視覺變化、切換導航目标 以及 處理通用的UI事件。
Transition:可互動元件有4種視覺狀态:正常(normal), 高亮(highlighted), 按下(pressed)和 禁用(disabled)。Selectable 依據使用者的輸入和自己目前的狀态執行狀态切換,切換狀态的視覺效果有4種類型:none、color tint、sprite swap 和 animation。使用 animation 效果必須再加入一個 animator 元件,此動畫控制器含有上述4種狀态。
能夠通過Auto Generate Animation button自己主動加入元件并建立動畫控制器。
Navigation:能夠使用鍵盤和遊戲控制器切換導航目标,假設你要開發一個僅使用遊戲控制器就能夠玩的遊戲(主機遊戲)。那麼這個功能很重要。由于玩家沒有滑鼠也無法使用觸摸屏,僅僅能通過button來切換導航目标。
這個功能被設計的很完好,以至于你差點兒什麼都不用做就能夠處理的很好。一共同擁有5種導航選項:不使用(None)、水準(Horizontal)、垂直(Vertical)、自己主動(Automatic)、顯式指定(Explicit)。在非顯式指定的情況下。導航系統依據每一個UI元素的矩形位置和大小。自己主動查找4個方向上是否存在最合适的切換目标。
假設選擇顯式指定,須要為4個方向指定切換目标(Selectable)。在Inspector 界面點選 Visualize button能夠檢視導航路徑(下圖中的黃色線條),在 EventSystems 中能夠設定預設選中的對象。
通用事件:OnSelect, OnDeselect, OnPointEnter, OnPointExit, OnPointDown, OnPointUp, ... 。重寫這些方法來定義自己的可互動元件。文末将通過一個樣例來說明怎樣實作自己定義控件。
Auto Layout
自己主動布局用于簡化UI的布局工作。自己主動布局基于 RectTransform 的布局系統。包括 布局元素(Layout Elements) 和 布局控制器(Layout Controllers)兩個概念。
布局元素含有 最小尺寸、首選尺寸 和 可選尺寸 這些參數,布局控制器依據這些參數來調整布局元素的大小和位置。
布局控制器調整的基本原則是:首先配置設定最小尺寸,然後假設還有足夠空間就配置設定首選尺寸,最後假設還有空間則配置設定可選尺寸。一個含有 RectTransform 元件的遊戲對象就是一個布局元素。
加入某些元件會改動布局元素的參數。LayoutElement 是一個用來改動預設布局參數的元件。
布局控制器以多種元件的形式存在,它們控制自身或子級的布局元素的大小和位置。關于各種布局控制器元件的功能和用法請參考 Unity 文檔。
Rich Text
預設情況下一個 Text 元件以單一樣式顯示全部文本,使用富文本能夠讓顯示樣式更豐富,比方高亮部分文本。
實際上,富文本功能不僅能夠用在 UI 系統,還能夠用在 Legacy GUI 系統 和 Debug 中。
富文本用法相似 html 标簽,比方 "<b>Hello</b>" 将顯示為加粗的 "Hello"。這些标簽還能夠嵌套使用。可用的标簽有 b(加粗)、i(傾斜)、size(大小)和 color (顔色)。當中 size 和 color 必須指定屬性值,如:"<size=50>Hello</size>" "<color=#FF0080FF>Hello</color>"。size 屬性的機關是像素,color 屬性使用RGBA格式的16進制表示顔色或直接填寫經常使用顔色名稱。下圖為使用示範樣例。
假設使用 TextMesh,還能夠使用 material 和 quad 标簽。material 須要指定 material 數組中的 material 下标,如 "<material=1>Cool</material>";quad 标簽沒有結束标簽,通經常使用來在文本中顯示一個圖檔,如 "This is me: <quad material=2 size=24 x=0 y=0 width=1 height=1 />"。
UnityEvent
一個可序列化的、可顯示在 Inspector 上的事件類型。典型的用途就是 Button 的 OnClick 事件。拖拽一個對象或元件到方框中,就能夠選擇事件觸發時調用的方法。可選方法必須是公開的、無傳回值的、含有0個或1個可序列化的參數。也能夠調用 set 類型的屬性。
你也能夠在自己的腳本裡使用 UnityEvent。僅僅要定義一個序列化的字段。就能夠和 OnClick 看起來一樣了!
UnityEvent 能夠通過代碼加入、移除或調用方法,是對 C# 的 delegate 的包裝。
另外還有泛型版本号的 UnityEvent,最多支援 4 個參數。隻是由于是泛型抽象類。須要先繼承再使用。
UnityEvent 是從程式裡通過 Invoke 方法調用的,Invoke 須要的參數類型和數量與泛型參數一緻。可是,Inspector上依舊僅僅能填寫0個或1個參數,在 Inspector 上加入的方法是無法直接獲得 Invoke 時傳遞的參數的。
自己定義控件
通過此自己定義控件的樣例,來說明怎樣靈活運用 UI 系統各種功能實作各種奇葩需求。
需求:實作一種角色點數配置設定的控件,角色有一定數量的點數,能夠配置設定給多種屬性,每種屬性都能夠配置設定一定範圍的點數,各屬性點數之和不能超過角色擁有的點數。一般的實作方法是,為每一個角色顯示剩餘點數和多條屬性滑塊。拖動每一個滑塊會改變剩餘點數。這裡我們要求把全部滑塊放到一個大滑動條中,能夠直接拖動每一個滑塊。這種優點是能夠直覺的看到每一個角色總能力對照以及剩餘可配置設定點數。
例如以下為設計圖。
我們先分析這個需求:整個滑動條代表點數總量。全部滑塊是左對齊拼接的。每一個滑塊具有自身最大值、最小值限制。全部滑塊總長度不超過整個滑動條。每一個滑塊是可互動的。能夠得到初步的設想是,每一個滑塊擁有一個繼承 Selectable 的元件,重寫按下和彈起的事件,在這個過程中,控制滑塊的長度。可是怎樣保持全部滑塊始終左對齊呢?一種直接的想法是使用水準自己主動布局。可是這裡我們不這麼做(你能夠試試這樣來實作),而是充分利用 RectTransform 錨點的功能,讓每一個滑塊對其到前一個滑塊的右端。這樣要求每一個滑塊是前一個滑塊的子級。
解決方式有了,再考慮一下讓這件事情更簡單、更通用一些。全部初始參數填寫在一個根部的元件裡。這個元件依據這些參數來自己主動建立全部滑塊。那麼一個滑塊須要的參數大概就是這種吧:
min、max、value 分别為 最小點數、最大點數 和 初始點數。最後一個 ValueSlider 就是我們自己定義的 Selectable 元件。在屬性裡儲存相應的元件引用友善對其進行改動。
ValueSlider 定義例如以下:
初始化的時候儲存根部元件(起個名字叫“多屬性滑動條”)和相應的屬性引用,然後按下和彈起時分别調用根部元件的開始滑動、結束滑動方法。
沒有什麼實際的内容,基本的操作都在根部元件上。根部元件定義例如以下:
這個樣例忽略這一步。
// 統計已使用的點數
int valueCount = 0;
for(int i=0; i<_attributes.Length; i++)
{
valueCount += _attributes[i].value;
}
// 計算剩餘點數
_restValue = _totalValue - valueCount;
RectTransform lastParent = transform as RectTransform;
// 計算一個點數相應的像素大小
pixelsPerPoint = lastParent.sizeDelta.x / _totalValue;
// 建立每一個滑塊。更好的做法是,在自己定義編輯器中使用一個button來生成全部滑塊
GameObject slider = new GameObject(_attributes[i].name);
// 初始化 RectTransform
RectTransform rect = slider.AddComponent<RectTransform>();
rect.SetParent(lastParent, false);
rect.localScale = Vector3.one;
rect.localRotation = Quaternion.identity;
rect.pivot = new Vector2(0, 0.5f);
rect.anchoredPosition = Vector2.zero;
if (i == 0)
rect.anchorMin = Vector2.zero;
rect.anchorMax = new Vector2(0, 1);
else
rect.anchorMin = new Vector2(1, 0);
rect.anchorMax = Vector2.one;
rect.sizeDelta = new Vector2(pixelsPerPoint * _attributes[i].value, 0);
// 初始化 Image
Image image = slider.AddComponent<Image>();
image.sprite = _attributes[i].image;
image.color = _attributes[i].color;
image.type = Image.Type.Sliced;
image.fillCenter = true;
// 初始化 ValueSlider
_attributes[i].valueSlider = slider.AddComponent<ValueSlider>();
_attributes[i].valueSlider.Init(this, _attributes[i]);
// 将目前 RectTransform 作為下一個滑塊的父級
lastParent = rect;
// 更新滑塊的值
void Update()
if(_currentAttribute != null)
// 計算滑動距離相應的點數變化
int deltaValue = Mathf.RoundToInt((_eventData.position.x - _eventData.pressPosition.x) / pixelsPerPoint);
// 受最小、最大值限制的點數變化
deltaValue = Mathf.Clamp(_beginValue + deltaValue, _currentAttribute.min, _currentAttribute.max) - _beginValue;
// 更新剩餘點數
_restValue = _beginRestValue - deltaValue;
// 假設剩餘點數用完,須要降低點數變化
if(_restValue < 0)
deltaValue += _restValue;
_restValue = 0;
// 更新目前點數
_currentAttribute.value = _beginValue + deltaValue;
// 更新滑塊大小
(_currentAttribute.valueSlider.transform as RectTransform).sizeDelta
= new Vector2(pixelsPerPoint * _currentAttribute.value, 0);
代碼的含義在上面的分析和凝視裡寫的很清晰了。不再贅述。這個元件最好再配合一個自己定義的編輯器,可是這裡就不想寫了,假設你感興趣能夠試試。
以下就是測試。建立一個滑動條背景。加入此腳本,填寫參數。最後看起來這種:
然後執行起來吧。圖就不截了,就是上面的設計圖......最後再來張合影。
加入 CanvasGroup 元件能夠控制整個子級的可互動性、不透明度。對制作非互動 UI 對象或總體控制一個窗體的不透明度很友善。
本文轉自mfrbuaa部落格園部落格,原文連結:http://www.cnblogs.com/mfrbuaa/p/5251628.html,如需轉載請自行聯系原作者