最近在接触FairyGUI,这是一个第三方的UI编辑器。支持的引擎非常多,包括Cocos,Ergt,Unity等等,接下来的版本还会支持UE4。这里简单记录一下,如何在Xlua中调用我们在FairyGUI编辑器中制作的界面。

编辑界面

首先,我们在编辑器随便制作一个组件,FairyGUI 中的一个界面就是一个组件,然后,我们往里面添加一些内容,比如文本框,按钮等等。我们把添加的组件设置为导出,在资源库视图中,我们选中这个组件,然后点击右键菜单,设置为导出。设置为导出的资源,会在图标上有个红色标记。

现在我们把StartUI和CityListUI 设置成为了导出,然后我们设置一下导出设置,也就是我们需要设置一下导出文件的存放路径。

这个我们通过发布设置按钮打开。我们根据自己项目需求,设置自己方便的一个路径。然后我们点击发布按钮。我们能在发布路径看见发布成功的文件。

如果我们界面中没有图片,也就不会存在一个atlas0.png这个图片。现在我们把这2个文件拷贝到Unity工程中的Asset的目录。现在我们放在Assets/Widgets/下面。

XLua中调用

FairyGUI创建界面,是通过FAiryGUI.UIPackage类来创建的。分为2步,第一步加载包,第二步创建界面组件。

第一步
UIPackage.AddPackage(assetResName);
assetResName 是从Assets 开始的目录,这里就是Assets/Widgets/Common。我们需要注意一点就是,我们不需要文件的_fui.bytes。这一部分会被API自动添加。然后我们的Common就是我们包名。我们添加了这个包,就能创建包里面导出的内容。

第二步
GObject obj = UIPackage.CreateObject(“Common”, “StartUI”);

现在我们拿到了obj 对象,这个不是GameObject。我们需要使用GRoot中来添加这个界面显示出来。
因为XLua默认是通过CS.namespace.classname命名的,为了方便使用,我们创建了一个lua 文件,里面从新定义了一下FairyGUI 中类的名字:

EventContext = CS.FairyGUI.EventContext
EventListener = CS.FairyGUI.EventListener
EventDispatcher = CS.FairyGUI.EventDispatcher
InputEvent = CS.FairyGUI.InputEvent
NTexture = CS.FairyGUI.NTexture
Container = CS.FairyGUI.Container
Image = CS.FairyGUI.Image
Stage = CS.FairyGUI.Stage
Controller = CS.FairyGUI.Controller
GObject = CS.FairyGUI.GObject
GGraph = CS.FairyGUI.GGraph
GGroup = CS.FairyGUI.GGroup
GImage = CS.FairyGUI.GImage
GLoader = CS.FairyGUI.GLoader
GMovieClip = CS.FairyGUI.GMovieClip
TextFormat = CS.FairyGUI.TextFormat
GTextField = CS.FairyGUI.GTextField
GRichTextField = CS.FairyGUI.GRichTextField
GTextInput = CS.FairyGUI.GTextInput
GComponent = CS.FairyGUI.GComponent
GList = CS.FairyGUI.GList
GRoot = CS.FairyGUI.GRoot
GLabel = CS.FairyGUI.GLabel
GButton = CS.FairyGUI.GButton
GComboBox = CS.FairyGUI.GComboBox
GProgressBar = CS.FairyGUI.GProgressBar
GSlider = CS.FairyGUI.GSlider
PopupMenu = CS.FairyGUI.PopupMenu
ScrollPane = CS.FairyGUI.ScrollPane
Transition = CS.FairyGUI.Transition
UIPackage = CS.FairyGUI.UIPackage
Window = CS.FairyGUI.Window
GObjectPool = CS.FairyGUI.GObjectPool
Relations = CS.FairyGUI.Relations
RelationType = CS.FairyGUI.RelationType
UIPanel = CS.FairyGUI.UIPanel
UIPainter = CS.FairyGUI.UIPainter
TypingEffect = CS.FairyGUI.TypingEffect

上面的内容,我们require 一次即可。然后我们把上面创建的GObject添加到界面上:

GRoot.inst:AddChild(obj);

到这里,我们就把界面添加到窗口上了,如何我们要关闭这个界面,我们使用:

GRoot.inst:RemoveChild(obj)

上面是关闭了界面,但是没有真正的释放,要释放这个资源,我们要使用GObject的Dispose()方法。

obj:Dispose()

好了,这里就能把界面调用出来了。

附加内容

这里附加一些Lua代码,方便我们使用UI:

— 声明一个 lua class
— className 是类名
— super 为父类
function class(className, super)
— 构建类
local clazz = { __cname = className, super = super }
if super then
— 设置类的元表,此类中没有的,可以查找父类是否含有
setmetatable(clazz, { __index = super })
end
— new 方法创建类对象
clazz.new = function(…)
— 构造一个对象
local instance = {}
— 设置对象的元表为当前类,这样,对象就可以调用当前类生命的方法了
setmetatable(instance, { __index = clazz })
if clazz.ctor then
clazz.ctor(instance, …)
end
return instance
end
return clazz
end

--UIBase.lua
UIBase = class("UIBase")

function UIBase:ctor(packageName,resName)
	self.Root = nil
	self.UIPkgName = packageName
	self.ResName = resName
end

function UIBase:OnInit()
	local obj = CS.ResLoader.Get():LoadFairyUI(self.UIPkgName,self.ResName)
	self.Root = obj 
	self:OnStart()
end

function UIBase:Show()
	GRoot.inst:AddChild(self.Root.asCom)
	self:OnShow()
end

function UIBase:Close()
	self:OnHide()
	GRoot.inst:RemoveChild(self.Root)
end

function UIBase:Dispose()
	self:OnDestory()
	self.Root:Dispose()
	self.Root = nil
end

function UIBase:OnStart()
end

function UIBase:OnShow()
end

function UIBase:OnHide()
end

function UIBase:OnDestory()
end
--UIManager.lua
--require "UIBase"

UIManager = {
	UIList = {},
	UIResMap = {},
	UIClass = {}
}

function UIManager.BindUIClass(className,classObj)
	if UIManager.UIClass[className] or classObj == nil then
		return
	end
	UIManager.UIClass[className] = classObj
end

function UIManager.BindAllUIClass()
	UIManager.BindUIClass("LoginUI",require "UI/LoginUI")
	UIManager.BindUIClass("CityListUI",require "UI/CityListUI")
end

function UIManager.OpenUI(uiName)
	local ui = UIManager.UIList[uiName]
	if ui == nil then
		ui = UIManager.UIClass[uiName].new()
		ui:OnInit()
		UIManager.UIList[uiName] = ui
	end
	ui:Show()
end

function UIManager.CloseUI(uiName)
	local ui = UIManager.UIList[uiName]
	if ui == nil then
		return
	end
	ui:Close()
end

function UIManager.ClearAllUI()
	for k ,v in pairs(UIManager.UIList) do
		v:Close()
		v:Dispose()
	end
end
--LoginUI.lua
local LoginUI = class("LoginUI",UIBase.new("Common","StartUI"))

function LoginUI:ctor()
end

function LoginUI:OnStart()
	print("Login UI OnStart")
	
	AddButtonClickEvent(self.Root,"n1",function() 
		print("Touch Start Game")
		UIManager.OpenUI("CityListUI")
		self:Close()
	end)

end

function LoginUI:OnDestory()
	RemoveButtonClickEvent(self.Root,"n1")
end

return LoginUI
--UIFunction.lua
--这些是关于FairyGUI的UI操作

function GetButton(root,path)
	local com =  path and root:GetChild(path) or root
	return com and com.asButton or nil
end

function GetList(root,path)
	local com =  path and root:GetChild(path) or root
	return com and com.asList or nil
end

function SetListRenderFunc(listCom,num,func)
	listCom.itemRenderer = CS.FairyGUI.ListItemRenderer(func)
	listCom.numItems = num
end

function GetText(root,path)
	local com =  path and root:GetChild(path) or root
	return com and com.asLabel or nil
end

function SetTextFiled(root,path,str)
	local com =  path and root:GetChild(path) or root
	if com then
		com.asTextField.text = str
	end
end

function AddButtonClickEvent(root,path,func)
	local com =  path and root:GetChild(path) or root
	if com then
		com.asButton.onClick:Add(func)
	end
end

function RemoveButtonClickEvent(root,path)
	local com =  path and root:GetChild(path) or root
	if com then
		com.asButton.onClick:Clear()
	end
end

function SetButtonClickEvent(root,path,func)
	local com = path and root:GetChild(path) or root
	if com then
		com.asButton.onClick:Set(func)
	end
end