UGUI-IMGUI 布局模式
固定布局與自動布局
使用 IMGUI 系統(tǒng)時,可使用兩種不同的模式來排列和組織 UI:固定布局模式和自動布局模式。到目前為止,本指南中提供的每個 IMGUI 示例都使用了固定布局。要使用自動布局,應(yīng)在調(diào)用控件函數(shù)時寫入?GUILayout?而不是?GUI。不必使用一種布局模式來替代另一種布局模式,可在同一?OnGUI()?函數(shù)中同時使用這兩種模式。
當有預(yù)先設(shè)計好的界面可供使用時,采用固定布局比較合理。如果預(yù)先不知道需要多少元素,或者不想費心進行每個控件的手動定位,則采用自動布局比較合適。例如,如果要基于保存游戲文件創(chuàng)建大量不同的按鈕,但無法準確知道要繪制多少按鈕,這種情況下采用自動布局可能會更加合理。具體實際上取決于游戲設(shè)計以及所需的界面呈現(xiàn)方式。
使用自動布局時有兩個主要的不同之處:
使用?GUILayout?而不是?GUI
自動布局控件不需要?Rect()?函數(shù)
/* 使用自動布局時的兩個主要不同之處 */
// JavaScript
function OnGUI()
{
? ? // 固定布局
? ? GUI.Button(Rect(25, 25, 100, 30), "I am a Fixed Layout Button");
? ? // 自動布局
? ? GUILayout.Button("I am an Automatic Layout Button");
}
// C#
using UnityEngine;
using System.Collections;
public class GUITest : MonoBehaviour
{
? ? void OnGUI()
? ? {
? ? ? ? // 固定布局
? ? ? ? GUI.Button(new Rect(25, 25, 100, 30), "I am a Fixed Layout Button");
? ? ? ? // 自動布局
? ? ? ? GUILayout.Button("I am an Automatic Layout Button");
? ? }
}
排列控件
根據(jù)使用的布局模式,可通過不同的掛鉤來控制控件的位置以及控件如何組合在一起。在固定布局中,可將不同的控件放入__組__中。在自動布局中,可將不同的控件放入__區(qū)域、水平組__和__垂直組__中
固定布局 - 組
組是固定布局模式中的布局規(guī)則。使用組可以定義包含多個控件的屏幕區(qū)域。為定義組中包含的控件,需要使用?GUI.BeginGroup()?和?GUI.EndGroup()?函數(shù)。組內(nèi)的所有控件將根據(jù)組的左上角而不是屏幕的左上角進行定位。因此,如果在運行時重新定位組,則將保持組中所有控件的相對位置。
例如,在屏幕上使多個控件居中非常容易。
/* 使用組在屏幕上使多個控件居中 */
// JavaScript
function OnGUI()
{
? ? // 在屏幕中央創(chuàng)建一個組
? ? GUI.BeginGroup(Rect(Screen.width / 2 - 50, Screen.height / 2 - 50, 100, 100));
? ? // 現(xiàn)在所有矩形都調(diào)整到該組。(0,0) 是該組的左上角。
? ? // 我們將創(chuàng)建一個框形,以便能看到該組在屏幕上的位置。
? ? GUI.Box(Rect(0, 0, 100, 100), "Group is here");
? ? GUI.Button(Rect(10, 40, 80, 30), "Click me");
? ? // 結(jié)束我們上面開始的組。記住這一點非常重要!
? ? GUI.EndGroup();
}
// C#
using UnityEngine;
using System.Collections;
public class GUITest : MonoBehaviour
{
? ? void OnGUI()
? ? {
? ? ? ? // 在屏幕中央創(chuàng)建一個組
? ? ? ? GUI.BeginGroup(new Rect(Screen.width / 2 - 50, Screen.height / 2 - 50, 100, 100));
? ? ? ? // 現(xiàn)在所有矩形都調(diào)整到該組。(0,0) 是該組的左上角。
? ? ? ? //我們將創(chuàng)建一個框形,以便能看到該組在屏幕上的位置。
? ? ? ? GUI.Box(new Rect(0, 0, 100, 100), "Group is here");
? ? ? ? GUI.Button(new Rect(10, 40, 80, 30), "Click me");
? ? ? ? // 結(jié)束我們上面開始的組。記住這一點非常重要!
? ? ? ? GUI.EndGroup();
? ? }
}

還可以將多個組嵌套在一起。這樣做時,每個組的內(nèi)容都會裁剪到其父項空間。
/* 使用多個組裁剪顯示的內(nèi)容 */
// JavaScript
var bgImage : Texture2D; // 256 x 32 的背景圖像
var fgImage : Texture2D; // 256 x 32 的前景圖像
var playerEnergy = 1.0; // 介于 0.0 和 1.0 之間的浮點數(shù)
function OnGUI()
{
? ? // 創(chuàng)建一個組來包含這兩個圖像
? ? // 調(diào)整前 2 個坐標以將其放在屏幕上的其他位置
? ? GUI.BeginGroup(Rect(0, 0, 256, 32));
? ? // 繪制背景圖像
? ? GUI.Box(Rect(0, 0, 256, 32), bgImage);
? ? // 創(chuàng)建將被裁剪的第二個組
? ? // 我們想要裁剪圖像而不是縮放圖像,這就是我們需要第二個組的原因
? ? GUI.BeginGroup(Rect(0, 0, playerEnergy * 256, 32));
? ? // 繪制前景圖像
? ? GUI.Box(Rect(0, 0, 256, 32), fgImage);
? ? // 結(jié)束這兩個組
? ? GUI.EndGroup();
? ? GUI.EndGroup();
}
// C#
using UnityEngine;
using System.Collections;
public class GUITest : MonoBehaviour
{
? ? // 256 x 32 的背景圖像
? ? public Texture2D bgImage;
? ? // 256 x 32 的前景圖像
? ? public Texture2D fgImage;
? ? // 介于 0.0 和 1.0 之間的浮點數(shù)
? ? public float playerEnergy = 1.0f;
? ? void OnGUI()
? ? {
? ? ? ? // 創(chuàng)建一個組來包含這兩個圖像
? ? ? ? // 調(diào)整前 2 個坐標以將其放在屏幕上的其他位置
? ? ? ? GUI.BeginGroup(new Rect(0, 0, 256, 32));
? ? ? ? // 繪制背景圖像
? ? ? ? GUI.Box(new Rect(0, 0, 256, 32), bgImage);
? ? ? ? // 創(chuàng)建將被裁剪的第二個組
? ? ? ? // 我們想要裁剪圖像而不是縮放圖像,這就是我們需要第二個組的原因
? ? ? ? GUI.BeginGroup(new Rect(0, 0, playerEnergy * 256, 32));
? ? ? ? // 繪制前景圖像
? ? ? ? GUI.Box(new Rect(0, 0, 256, 32), fgImage);
? ? ? ? // 結(jié)束這兩個組
? ? ? ? GUI.EndGroup();
? ? ? ? GUI.EndGroup();
? ? }
}

自動布局 - 區(qū)域
區(qū)域僅用于自動布局模式。區(qū)域定義了有限的屏幕區(qū)域來包含 GUILayout 控件,因此在功能上類似于固定布局組。由于自動布局的性質(zhì),幾乎始終要用到區(qū)域。
在自動布局模式下,不需要在控制級別定義繪制控件的屏幕區(qū)域??丶⒆詣臃胖迷诎摽丶膮^(qū)域的最左上角。此區(qū)域可能是指屏幕。此外也可以創(chuàng)建手動定位的區(qū)域。一個區(qū)域內(nèi)的 GUILayout 控件將放置在該區(qū)域的最左上角。
/* 未放置在任何區(qū)域的按鈕以及放置在屏幕中間區(qū)域的按鈕。*/
// JavaScript
function OnGUI()
{
? ? GUILayout.Button("I am not inside an Area");
? ? GUILayout.BeginArea(Rect(Screen.width / 2, Screen.height / 2, 300, 300));
? ? GUILayout.Button("I am completely inside an Area");
? ? GUILayout.EndArea();
}
// C#
using UnityEngine;
using System.Collections;
public class GUITest : MonoBehaviour
{
? ? void OnGUI()
? ? {
? ? ? ? GUILayout.Button("I am not inside an Area");
? ? ? ? GUILayout.BeginArea(new Rect(Screen.width / 2, Screen.height / 2, 300, 300));
? ? ? ? GUILayout.Button("I am completely inside an Area");
? ? ? ? GUILayout.EndArea();
? ? }
}
請注意,在一個區(qū)域內(nèi),具有可見元素(如按鈕和框形)的控件會將寬度拉伸到該區(qū)域的整個長度。
自動布局 - 水平和垂直組
使用自動布局時,默認情況下控件將從上到下依次出現(xiàn)。在很多情況下,需要更精確控制控件的放置位置以及排列方式。如果使用自動布局模式,則可以選擇水平和垂直組。
與其他布局控件一樣,可以調(diào)用單獨的函數(shù)來開始或結(jié)束這些組。這些函數(shù)為?GUILayout.BeginHoriztontal()、GUILayout.EndHorizontal()、GUILayout.BeginVertical()?和?GUILayout.EndVertical()。
水平組內(nèi)的所有控件都將始終采用水平布局方式。垂直組內(nèi)的所有控件都將始終采用垂直布局方式。這聽起來很簡單,但若要將組嵌套在彼此內(nèi)部,就不那么簡單了。通過嵌套的方式可在任何能夠想象的配置中排列任意數(shù)量的控件。
/* 使用嵌套的水平和垂直組 */
// JavaScript
var sliderValue = 1.0;
var maxSliderValue = 10.0;
function OnGUI()
{
? ? // 將所有控件包裹在指定的 GUI 區(qū)域中
? ? GUILayout.BeginArea(Rect(0, 0, 200, 60));
? ? // 開始單個水平組
? ? GUILayout.BeginHorizontal();
? ? // 正常放置按鈕
? ? if (GUILayout.RepeatButton("Increase max\nSlider Value"))
? ? {
? ? ? ? maxSliderValue += 3.0 * Time.deltaTime;
? ? }
? ? // 在按鈕旁邊垂直排列另外兩個控件
? ? GUILayout.BeginVertical();
? ? GUILayout.Box("Slider Value: " + Mathf.Round(sliderValue));
? ? sliderValue = GUILayout.HorizontalSlider(sliderValue, 0.0, maxSliderValue);
? ? // 結(jié)束這些組和區(qū)域
? ? GUILayout.EndVertical();
? ? GUILayout.EndHorizontal();
? ? GUILayout.EndArea();
}
// C#
using UnityEngine;
using System.Collections;
public class GUITest : MonoBehaviour
{
? ? private float sliderValue = 1.0f;
? ? private float maxSliderValue = 10.0f;
? ? void OnGUI()
? ? {
? ? ? ? // 將所有控件包裹在指定的 GUI 區(qū)域中
? ? ? ? GUILayout.BeginArea(new Rect(0, 0, 200, 60));
? ? ? ? // 開始單個水平組
? ? ? ? GUILayout.BeginHorizontal();
? ? ? ? // 正常放置按鈕
? ? ? ? if (GUILayout.RepeatButton("Increase max\nSlider Value"))
? ? ? ? {
? ? ? ? ? ? maxSliderValue += 3.0f * Time.deltaTime;
? ? ? ? }
? ? ? ? // 在按鈕旁邊垂直排列另外兩個控件
? ? ? ? GUILayout.BeginVertical();
? ? ? ? GUILayout.Box("Slider Value: " + Mathf.Round(sliderValue));
? ? ? ? sliderValue = GUILayout.HorizontalSlider(sliderValue, 0.0f, maxSliderValue);
? ? ? ? // 結(jié)束這些組和區(qū)域
? ? ? ? GUILayout.EndVertical();
? ? ? ? GUILayout.EndHorizontal();
? ? ? ? GUILayout.EndArea();
? ? }
}

使用 GUILayoutOption 定義一些控件
可使用 GUILayoutOption 覆蓋某些自動布局參數(shù)。要執(zhí)行此操作,可提供相應(yīng)的選項作為 GUILayout 控件的最終參數(shù)。
在上面的區(qū)域示例中,是否還記得按鈕的寬度擴展到區(qū)域?qū)挾鹊?100%?如果愿意,我們可以覆蓋這種行為。
/* 使用 GUILayoutOption 覆蓋自動布局控件屬性 */
//JavaScript
function OnGUI()
{
? ? GUILayout.BeginArea(Rect(100, 50, Screen.width - 200, Screen.height - 100));
? ? GUILayout.Button("I am a regular Automatic Layout Button");
? ? GUILayout.Button("My width has been overridden", GUILayout.Width(95));
? ? GUILayout.EndArea();
}
// C#
using UnityEngine;
using System.Collections;
public class GUITest : MonoBehaviour
{
? ? void OnGUI()
? ? {
? ? ? ? GUILayout.BeginArea(new Rect(100, 50, Screen.width - 200, Screen.height - 100));
? ? ? ? GUILayout.Button("I am a regular Automatic Layout Button");
? ? ? ? GUILayout.Button("My width has been overridden", GUILayout.Width(95));
? ? ? ? GUILayout.EndArea();
? ? }
}
關(guān)可能的 GUILayoutOption 的完整列表,請閱讀?GUILayoutOption 腳本參考頁面。