这两天在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
若有错误,欢迎指正,谢谢!