當你開始使用NGUI的時候,簡單的從項目視圖 中一個”Control”預設體 拖拽到場景視圖中,你將會發現 Hierarchy層次面板中會出現以下層次結構:
- 其中 UI Root作為根節點,是每個NGUI元素的頂級父節點
- 在Unity中,每個元素都具有最基本的Transform屬性,這也叫基元屬性;
- UI Root是用於管理和處理UI的變化和縮放
- Camera其實是一個獨立的UICamera,負責渲染UI對象到視圖中,作為UI Root的子節點存在
- 剩下的藍色文字的物體就是最關鍵的UI部分.
(一) UI Root縮放方式之 Scaling Style
- NGUI中 UI Root 縮放方式有三種,默認為Flexible
public enum Scaling
{
Flexible,
Constrained,
ConstrainedOnMobiles,
}
public Scaling scalingStyle = Scaling.Flexible;
Flexible style lets your UI always be in pixels, and a 300x200 widget will always take 300 by 200 pixels on the screen. This also means that viewing your UI on a low-res device will make your widgets appear rather large in size, and viewing your UI on a high-res device will make your widgets appear small. On the plus side, with this setting your UI will always remain as crisp as possible.
譯:Flexible style 靈活的方式讓你操作UI.比如你設置300*200 px的UI Root Fiexible,那么你的UI 元素將永遠保持在300 * 200 像素,並且不會進行任何縮放.也就是說在低分辨率的設備下你的UI畫面中的元素將會顯得非常大,而在高分辨率的設備中,你的UI畫面元素將會變得非常小. 唯一的好處就是這個UI將會保持這個分辨率,不會隨着畫面和設備而改變.當選擇這個選項的時候,不要忘記手動設置高度.
public Scaling activeScaling { get { Scaling scaling = scalingStyle; if (scaling == Scaling.ConstrainedOnMobiles) #if UNITY_EDITOR || UNITY_IPHONE || UNITY_ANDROID || UNITY_WP8 || UNITY_WP_8_1 || UNITY_BLACKBERRY return Scaling.Constrained; #else return Scaling.Flexible; #endif return scaling; } }他們之間的關系是:默認為Flexible,若手動選 Scaling.ConstrainedOnMobiles,應該符合的平台是編輯器,IPhone,安卓,Window Phone8或者Unity_WP_8_1,或者黑莓.那么這些情況將把UI Root縮放方式變為Scaling.Constrained,其他時候設置無效,將會默認為Flexible固定縮放,也就是說當你發布在網頁平台的時候設置為ConstrainedOnMobiles為無效操作.
Flexible 意味着保持原有像素,不進行縮放.分辨率的變化不影響UI的像素.
Unity默認按照UI Root Minimum Height 最小高度限制來設定 該UI元素的實際高度.
而且UI Root腳本中 默認最小高度為720px,最大高度為1280px
並且限定范圍為320px <= Height <= 1536px
比如當我們把屏幕的寬高度設置為1280 * 7200 px
那么在固定縮放的情況下,Scaling.Flexible中,實際高度activeHeight是怎么計算的呢?
if (scaling == Scaling.Flexible) { Vector2 screen = NGUITools.screenSize; float aspect = screen.x / screen.y; if (screen.y < minimumHeight) { screen.y = minimumHeight; screen.x = screen.y * aspect; } else if (screen.y > maximumHeight) { screen.y = maximumHeight; screen.x = screen.y * aspect; } // Portrait mode uses the maximum of width or height to shrink the UI int height = Mathf.RoundToInt((shrinkPortraitUI && screen.y > screen.x) ? screen.y / aspect : screen.y); // Adjust the final value by the DPI setting return adjustByDPI ? NGUIMath.AdjustByDPI(height) : height; }從腳本中我們可以得知,首先通過NGUITools.screenSize獲取實際屏幕寬高,然后求出寬高比aspect;
然后根據實際屏幕高度的與minimumHeight和maximumHeight相比取得限定范圍內合適的值
- 實際屏幕高度比最小高度小,設定實際屏幕高度為最小高度,然后根據比例aspect求出最終寬度;
- 實際屏幕高度比最大高度大,設定實際屏幕高度為最大高度,然后根據比例aspect求出最終寬度;
- 若實際屏幕高度在最大高度和最小高度之間,則不進行改變.
- 若收縮shrinkPortraitUI 且屏幕高度大於寬度,則進行比例壓縮,真實高度 = screen.y / aspect ,否則保持不變.
- 返回最終結果.
好奇的是,NGUITools.screenSize是怎么獲取到我們設定的屏幕大小的呢?
#if UNITY_EDITOR static int mSizeFrame = -1; static System.Reflection.MethodInfo s_GetSizeOfMainGameView; static Vector2 mGameSize = Vector2.one; /// <summary> /// Size of the game view cannot be retrieved from Screen.width and Screen.height when the game view is hidden. /// </summary> static public Vector2 screenSize { get { int frame = Time.frameCount; if (mSizeFrame != frame || !Application.isPlaying) { mSizeFrame = frame; if (s_GetSizeOfMainGameView == null) { System.Type type = System.Type.GetType("UnityEditor.GameView,UnityEditor"); s_GetSizeOfMainGameView = type.GetMethod("GetSizeOfMainGameView", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); } mGameSize = (Vector2)s_GetSizeOfMainGameView.Invoke(null, null); } return mGameSize; } }原來在編輯器模式中,通過反射獲取到類型 System.Type.GetType("UnityEditor.GameView,UnityEditor"); 通過類型獲取到方法 type.GetMethod("GetSizeOfMainGameView", 最后調用方法得到屏幕大小.
接下來我們用案例來看UI實際情況:首先設置屏幕大小為1270*720ox
把UI Root 的最小Minimum 設置為 720px,也就是以此 UI Root為畫布的元素(畫布和屏幕大小一致),默認與畫布的比例是自身元素高度 : 720px
如我們把Button設置的寬高設置為72 px * 1280 px,那么剛好 10個Button元素就能把畫面填充滿
最頂部Button元素的坐標Y軸是324,那么它是怎么來的呢?
計算:屏幕高度 / 2 - 元素高度 /2 = 720/2 – 72/2 = 324 px
這在做網格類游戲很有用哦:比如三消游戲或者SLG游戲等
(二) UI Root縮放方式之 Constrained
- Constrained is the exact opposite of that. When the UIRoot is set to this setting, your screen will always remain the same size as far as NGUI is concerned, regardless of the actual screen size. This means that if a 300x200 widget takes 25% of your screen with the resolution of 1920x1080, it will still take 25% of the screen when you drop your resolution to 1280x720. If you don't want to worry about how your UI will look at different screen sizes and you don't care much about making it as crisp as possible, choose this setting. Don't forget to set the Content dimensions setting when choosing this option.
- You can further refine the constrain by choosing whether the content will Fit on the screen or whether it will Fill the screen (when 'fit' is off). Think of it as your Desktop wallpaper. When you choose the Fit method, the wallpaper will always be fully visible on the screen, where if you go with a Fill method, it will always completely fill the screen while maintaining its aspect ratio. Same idea here. See the attached image for more information.
- 譯:Constrained 約束縮放方式正好相反,無論你的屏幕分辨率是多少,UI元素將會保持着最適合的縮放方式渲染在屏幕中,元素的大小看起來無論在任何分辨率的設備都是一致的. 只是在低分辨率的設備中,元素會壓縮而變得更清晰,但是在高分辨率的設備中,為了保持同等大小,可能會進行拉伸而顯得沒那么清晰.
- 你可以進一步約束,使得它填充滿屏幕,並且寬高比不變(也就是說部分元素會溢出在屏幕之外) 根據百分比縮放,大小可能會失真.
(三) UI Root縮放方式之 ConstrainedOnMobiles
- ConstrainedOnMobiles setting is a combination of the two. It will behave as if the setting was "Flexible" on desktop builds, and it will act as if the size was "Constrained" when targeting mobile platforms.
- ConstrainedOnMobiles設置是兩者的結合。它將表現得好像設置桌面構建“靈活”,它的“約束”只是針對移動平台。
UI Root 廣播機制
static void UIRoot.Broadcast ( string funcName ) static Broadcast the specified message to the entire UI. static void UIRoot.Broadcast ( string funcName, object param ) static Broadcast the specified message to the entire UI.
對UI的顯示有影響的不只是UI Root的縮放方式,UI 元素的大小,錨點的設置,還有攝像機的Size哦
- 對於相同的元素,默認攝像機大小Size為1,UI攝像機使用的是正交投射方式,Size控制正交攝像機的視窗口大小
- 當畫布大小為1280*720 ,正好鋪滿畫布的元素大小為 1280*720,在Size為1 的攝像機中完美的渲染到屏幕中,不產生任何裁剪和填充
- 當我們更改正交攝像機的Size為0.5時,情況是怎樣的呢?
- 這是為什么呢?因為攝像機在Size為1的時候,能渲染1280*720的像素,當Size減小為一半的時候,意味着攝像機視窗口能渲染的東西少了一半,也就是只有640*320像素元素了,這反而看起來是攝像機Size小了,元素反而還變大了…
- 在下節中會詳細的介紹Unity中的攝像機,謝謝關注