這兩天在Github上發現了xlua的做者車雄生前輩開源的一個框架—XUUI,因而下載下來學習了一下。XUUI基於xlua,又借鑑了mvvm的設計概念。xlua是目前很火的unity熱更方案,不只支持純lua腳本熱更,也能夠作 C# 代碼的bug hotfix,而mvvm框架呢,在前端開發中應用很廣,我周圍同事在作wpf開發時也用到了mvvm框架,mvvm模式在unity開發中也一樣適用,github上能夠找到很多開源案例。XUUI主要有兩大核心能力:一是支持MVVM的單向、雙向綁定,二是框架應用時能夠作模塊加載、模塊刷新、模塊間數據隔離、模塊間可控交互。
做者在文檔中介紹了XUUI框架的特色:一是能夠和任意UI庫配合,ugui,ngui,fairyGUI,你本身倒騰的UI庫均可以;二是支持把本框架做爲一個mvvm驅動器,純用C#寫邏輯;三是支持「計算屬性」:「計算屬性」依賴的各屬性發生改變會觸發「計算屬性」的重計算;四是可隨時綁定View以及解綁定。
下載項目到本地,能夠看到做者提供了幾個使用示例。使用時要設置好綁定信息,給各個UI元素(好比Button、Text、InputField等)添加適配器,能夠經過Component/XUUI菜單或者手動到XUUI\Scripts\UGUIAdapter目錄找腳本拖放到UI上,而後設置BindTo屬性便可,XUUI做者已經提供了Button、Text、Dropdown、InputField的適配器,其餘ui元素好比Toggle就須要本身去編寫了,做者已經提供了接口模板,本身實現其餘適配器也不難。先來看一下Helloworld示例:
這個示例中,有三個ui元素,綁定信息以下:InputField: info.name;Text : message,這是個「計算屬性」,計算時用了info.name,當info.name發生變化會觸發message從新計算,並自動更新Text;Button : click,這會綁定到一個click command上。C#代碼以下:
using UnityEngine;
using XUUI;
public class Helloworld : MonoBehaviour
{
Context context = null;
void Start()
{
context = new Context(@"
return {
data = {
info = {
name = 'John',
},
},
computed = {
message = function(data)
return 'Hello ' .. data.info.name .. '~!'
end
},
commands = {
click = function(data)
print(data.info.name..'哈哈')
end,
},
}
");
context.Attach(gameObject);
}
void OnDestroy()
{
context.Dispose();
}
}
如上面C#代碼所示,首先要new一個Context,參數是個lua腳本,該lua腳本返回一個table,table須要包含幾個特殊的字段: data就是ViewModle(VM);computed中引用到的VM元素,在其依賴的VM元素髮生改變會自動從新計算並同步到各個綁定了它(好比上例的message)的節點;commands是相似按鈕點擊事件綁定的響應方法,隨後,調用Context的Attach方法進行綁定。
四、XUUI中幾個重要的類
(1)Context:啓動框架的方法就是new一個Context實例,並傳入lua腳本,在Context的構造函數中,會初始化好lua運行環境(即LuaEnv),並解析傳入的lua腳本,對框架各模塊進行配置,Context實現了IDisposable接口,以便對一些非託管資源進行手動的垃圾回收。
(2)DataConsumer:若是ui Adapter須要監聽VM變化,須實現DataConsumer接口(能夠不顯式聲明實現,只要有DataConsumer聲明的接口便可)
(3)DataProducer:若是ui Adapter須要把數據同步回VM,須實現DataProducer接口
(4)EventEmitter:若是ui Adapter須要產生一個事件,須實現EventEmitter接口
五、XUUI框架的應用
在實際使用中,並不會像上面HelloWorld實例那麼簡單,做者也提供了在實際使用時的示例,首先new一個Context,Context的構造函數傳入的是一個含modules字段以及name字段的table:
context = new Context(@"
return {
name = 'myapp',
modules = {'module1', 'module2'},
}
");
執行上面代碼,框架會作這些事情: 加載myapp.module1,myapp.module2,加載的規則和require是一致的;爲這兩個設置獨立的沙盒,各模塊即便定義了全局變量也互不影響,必定程度上減輕不一樣模塊開發者因爲溝通不足或者筆誤引起的模塊間衝突;模塊間數據隔離:模塊也能夠定義data、commands、computed,在模塊定義的commands和computed只能看到本模塊的data; 模塊間調用:經過exports字段能夠導出一些函數供其它模塊調用,其它模塊能夠經過「模塊名.函數名」調用
* 支持模塊刷新(reload),reload後data變更會更新UI,監聽原先commands也會自動更新到新的commands,computed會自動從新計算並更新UI。
module1代碼以下:
return {
data = {
name = "haha",
select = 0, -- ui經過 module1.select來綁定
},
commands = {
click = function(data)
module2.set_select(data.select) -- 能夠調用別的模塊exports的接口
data.select = data.select == 0 and 1 or 0 -- command只能看到/修改本身的數據
end,
},
computed = {
info = function(data)
return string.format('i am %s, my select is %d', data.name, data.select)
end,
},
exports = {
hello = function(p) -- 能夠被其它module調用
print('hello, p = '.. p)
end,
},
}
module2代碼以下:
local data = {
message = "hehe",
select = 1,
}
return {
data = data,
commands = {
click = function(data)
module1.hello(1)
data.select = data.select == 0 and 1 or 0
end,
},
computed = {
info = function(data)
return string.format('message is %s, select is %d', data.message, data.select)
end,
},
exports = {
set_select = function(p)
data.select = p
end,
},
}
須要注意的是:這裏的UI不像邏輯那樣劃分模塊,經過「模塊名.模塊內路徑」去進行數據/響應的綁定,好比moudle1.select,module2.click等等。
六、最後
昨天才接觸到這個框架,XUUI框架下載量並很少,今天大概學習了一下,分享一下學習成果,總的來講,這個框架集成了xlua和mvvm,有不少值得借鑑的地方,很適合ui模塊的開發。博客內容有部分是從做者文檔裏抄下來的,由於怕本身描述不許確。分享一下,但願這個框架能像基於ulua的SimpleFramework同樣被更多開發者使用~
項目地址:https://github.com/chexiongsheng/XUUI
若有錯誤,歡迎指正,謝謝!