FairyGUI筆記:Component(九)
-
Component
自定義資料
可以設定一個自定義的資料,這個資料FairyGUI不做解析,按原樣釋出到最後的描述檔案中。開發者可以在執行時獲取。獲取方式根據SDK版本有所不同,如果是支援XML包格式的SDK,獲取方式為:
//Unity/Cry
aComponent.packageItem.componentData.GetAttribute("customData");
//Cocos2dx/Vision
aComponent->getPackageItem()->componentData->RootElement()->Attribute("customData");
//LayaAir
aComponent.packageItem.componentData.getAttribute("customData");
//Egret
aComponent.packageItem.componentData.attributes.customData;
//AS3/Starling
[email protected];
如果是支援二進位制包格式的SDK,獲取方式為:
//Unity/Cry/Laya/Egret
aComponent.baseUserData;
//Cocos2dx/Vision
aComponent->getBaseUserData();
穿透
//true表示不可穿透,false表示可穿透。
aComponent.opaque = false;
注意:圖片和普通文字是不接受點選的,如果一個只含有圖片或普通文字的元件,設定了點選穿透,那麼整個元件就是完全穿透了,不會攔截到任何點選。
-
畫素點選測試
有些特殊需求,需要用到不規則區域的點選測試。首先你要準備一張包含不規則區域的圖片,圖片裡不透明的畫素代表接受點選的區域,透明的畫素代表點選穿透的區域,元件裡超出圖片範圍的也是可穿透的區域。
把這張圖片拖入舞臺,然後在元件的“畫素點選測試”屬性裡,選擇這張圖片。
-
遮罩
矩形遮罩
將元件的“溢位處理”設定為“隱藏”或者“滾動”,那麼元件就帶了矩形遮罩。超出元件(矩形區域-邊緣留空)的區域都不可見。無論在什麼平臺,這種遮罩的效率是最高的。
自定義遮罩
可以設定元件內一個圖片或者圖形作為元件的遮罩。這種遮罩一般都是使用模板測試(Stencil Op)技術。各個平臺支援的力度不同:
-
AS3/Starling/Egret/Laya
使用圖形(Graph)作為遮罩時,有圖形的區域內容可見,例如,一個圓形,則圓形區域內可見,其他區域不可見。不能使用圖片(Image)作為遮罩,因為使用圖片作為遮罩也是取其矩形區域而已,用一個矩形(Graph)的圖形效果是一樣的。
Starling版本要使用自定義遮罩必須在應用程式描述檔案里加上:
<initialWindow>
<depthAndStencil>true</depthAndStencil>
</initialWindow>
-
Unity
使用圖形(Graph)作為遮罩時,有圖形的區域內容可見,例如,一個圓形,則圓形區域內可見,其他區域不可見。使用圖片(Image)作為遮罩時,圖片內透明度為0的畫素對應區域的內容不可見,反之可見。超出圖片區域的內容不可見。
反向遮罩(挖洞)
效果和正常遮罩相反,也就是可見的區域變不可見,不可見的區域變可見。目前僅Unity平臺支援,例如:
使用圖形(Graph)作為遮罩時,有圖形的區域內容不可見,例如,一個圓形,則圓形區域內不可見,其他區域可見。
使用圖片(Image)作為遮罩時,圖片內透明度為0的畫素對應區域的內容可見,反之不可見。超出圖片區域的內容可見。
注意:
- 當遮罩發生時,點選測試也同樣會發生變化,只有顯示出來的內容才接受點選檢測,被遮住的內容不接受點選檢測。
- 對於正在編輯的元件,遮罩只有在預覽時才能看到效果。
- 定義了遮罩的元件,其內部的元件永遠無法和外部的元件合併Draw Call,因為他們有不同的材質屬性。
-
擴充套件
從提示可以看到,FairyGUI中“擴充套件”的定義方式是以”名稱約定“為基礎的。一個按鈕,可以帶有標題和圖示,這個標題(一般是一個文字)和圖示(一般是一個裝載器)需要你自己放置到元件中,並把他們名字設定為title和icon,就像這樣:
然後我們測試一下這個剛製作好的元件。把按鈕元件拖到另一個元件中,並設定一下“標題”和“圖示”,如下圖
效果出來了。這說明標題文字被自動設定到了名稱為“title”的文字元件上,圖示被自動設定到了名稱為“icon”的裝載器元件上。
如果按鈕元件裡沒有放置名稱為icon的裝載器控制元件呢?那麼設定圖示就沒有效果,僅此而已。其他約定的處理方式也相同。不會有任何報錯。
-
GComponent
元件支援動態建立,例如:
GComponent gcom = new GComponent();
gcom.SetSize(100,100);
GRoot.inst.AddChild(gcom);
動態建立的元件是空元件,可以作為其他元件的容器。一個常見的用途,如果你要建立一個多層的UI管理系統,那麼空元件就是一個合適的層級容器選擇。動態建立的元件預設是點選穿透的,也就是說如果直接new一個空元件作為接收點選用途,你還得這樣設定:
//設定元件點選不穿透。
gcom.opaque = true;
如果要建立UI庫裡的元件,應該使用這樣的方式:
GComponent gcom = UIPackage.CreateObject("包名","元件名").asCom;
GRoot.inst.AddChild(gcom);
FairyGUI和Flash/Cocos類似,採用樹狀的結構組織顯示物件。容器可以包含一個或多個基礎顯示物件,也可以包含容器。這個樹狀結構稱為顯示列表。FairyGUI提供了API管理顯示列表。
-
顯示列表管理
-
numChildren
獲得容器內孩子元件的數量。 -
AddChild
AddChildAt
向容器內新增元件。前者將元件新增到顯示列表的隊尾;後者可以指定一個索引控制元件的插入位置。 -
RemoveChild
RemoveChildAt
RemoveCihldren
從容器內刪除元件。當元件從顯示物件中移出時,將不再佔用顯示資源。但元件從顯示列表移出後,只是不顯示,並沒有銷燬,如果你沒有儲存這個物件的引用留待後續使用,或者沒有呼叫物件的Dispose方法銷燬物件,那麼會產生記憶體洩露。 -
GetChild
GetChildAt
通過索引或名稱獲得元件引用。元件的名字是允許重複的,在這種情況下,GetChild返回第一個匹配名稱的物件。 -
GetChildIndex
獲得指定元件在顯示列表中的索引。 -
SetChildIndex
SwapChildren
SwapChildrenAt
設定元件在顯示列表中的索引。 -
渲染順序
在FairyGUI中,顯示列表是以樹形組織的,下面說的渲染順序均指在同一個父元件下安排的順序,不同父元件的元件是不可能互相交錯的,這是前提,請注意。
顯示物件的渲染順序取決於它的顯示列表中的順序,順序大的後渲染,即顯示在較前面。一般來說,我們都是使用AddChild或SetChildIndex調整渲染順序。例如如果要一個元件顯示在容器的最前面,那呼叫AddChild(元件)就可以了,AddChild是可以重複呼叫的。也可以呼叫SetChildIndex設定物件在顯示列表中的具體位置,例如SetChildIndex(元件,0)就可以將元件置於最底層。
還有另外一個因子可以影響渲染循序,它就是GObject.sortingOrder。這個屬性只用於特定的用途,不作常規的使用。它一般用於類似固定置頂的功能,另外,永遠不要將sortingOrder用在列表中。sortingOrder越大,則渲染順序越後,即顯示到更前面的位置。一般情況下,sortingOrder為0,這時渲染順序由顯示物件在顯示列表中的順序決定。sortingOrder可以令你更靈活的控制渲染循序。例如,如果希望一個元件始終保持在其他元件上方,可以設定其sortingOrder一個較大的整數值,這樣無論容器使用AddChild添加了多少元件,這個元件依然顯示在最前面。(sortingOrder的效率較差,勿做頻繁呼叫的用途)
上面提到的都是調整物件在顯示列表中的順序,如果不想調整這個順序的同時,又要調整渲染順序,元件還提供了另一種方式。
//升序,這是預設值,按照物件在顯示列表中的順序,從小到大依次渲染,效果就是序號大的顯示在較前面。
aComponent.childrenRenderOrder = ChildrenRenderOrder.Ascent;
//降序,按照物件在顯示列表中的順序,從大到小依次渲染,效果就是序號小的顯示在較前面。
aComponent.childrenRenderOrder = ChildrenRenderOrder.Descent;
//拱形,需要指定一個頂峰的索引,從兩端向這個索引位置依次渲染,效果就是這個位置的物件顯示在最前面,兩邊的物件依次顯示在後面。
aComponent.childrenRenderOrder = ChildrenRenderOrder.Arch;
aComponent.apexIndex = 3; //索引為3的物件顯示在最前面。
-
繫結擴充套件類
可以繫結一個類為元件的擴充套件類。首先,編寫一個擴充套件類:
public class MyComponent : GComponent
{
GObject msgObj;
//如果你有需要訪問容器內容的初始化工作,必須在這個方法裡,而不是在建構函式裡。各個SDK的函式原型的引數可能略有差別,請以程式碼提示為準。
override protected void ConstructFromXML(XML xml)
{
base.ConstructFromXML(xml);
//在這裡繼續你的初始化
msgObj = GetChild("msg");
}
public void ShowMessage(string msg)
{
msgObj.text = msg;
}
}
然後註冊你的擴充套件類。注意,必須在元件構建前註冊,如果你使用的是UIPanel,那麼在Start裡註冊是不夠早的,必須在Awake裡,總之,如果註冊不成功,90%可能都是註冊晚於建立,10%可能是URL錯誤,這可以通過列印URL排查。
UIObjectFactory.SetPackageItemExtension("ui://包名/元件A”, typeof(MyComponent));
這樣就為元件A綁定了一個實現類MyComponent 。以後所有元件A創建出來的物件(包括在編輯器裡使用的元件A)都是MyComponent型別。然後我們就可以為MyComponent新增API,用更加面向物件的方式操作元件A。例如:
MyComponent gcom = (MyComponent)UIPackage.CreateObject(“包名“, ”元件A”);
gcom.ShowMessage("Hello world");
注意:如果元件A只是一個普通的元件,沒有定義“擴充套件”,那麼基類是GComponent,如上例所示;如果元件A的擴充套件是按鈕,那麼MyComponent的基類應該為GButton,如果擴充套件是進度條,那麼基類應該為GProgressBar,等等。這個千萬不能弄錯,否則會出現報錯。