一.起因
在客户端游戏开发中最让人恶心的工作就是UI相关的东西,虽然有了像cocostudio这样的可视化工具,但界面中有大量需要由代码访问的控件的时候,需要写太多重复的代码例如:
//加载UI配置文件
var root = ccs.uiReader.widgetFromJsonFile("res/cocosui/UIEditorTest/UIButton_Editor/UIButton_Editor_1.json");
this._mainNode.addChild(root);
//查询back控件,并添事件响应
var back_label = ccui.helper.seekWidgetByName(root, "back");
back_label.addTouchEventListener(this.backEvent,this);
//查询Button_123控件,并添事件响应
var button = root.getChildByName(root, "Button_123");
button.addTouchEventListener(this.touchEvent,this);
void on_控件名_信号名(参数);
ctor: function() {
this._super();
...
button.addTouchEventListener(this._onButtonEvent, this);
},
_onButtonEvent: function(sender, type) {
switch(type) {
case ccui.Widget.TOUCH_BEGAN:
...;
return true;
case ccui.Widget.TOUCH_MOVED:
...;
break;
case ccui.Widget.TOUCH_ENDED:
...;
break;
}
}
//触摸事件
sz.UILoader.touchEvents = ["TouchBegan", "TouchMoved", "TouchEnded"];
//控件事件列表
sz.UILoader.widgetEvents = [
//Button
{widgetType: ccui.Button, events: sz.UILoader.touchEvents},
//ImageView
{widgetType: ccui.ImageView, events: sz.UILoader.touchEvents},
//TextFiled
{widgetType: ccui.TextField, events: ["AttachWithIME", "DetachWithIME", "InsertText", "DeleteBackward"]},
//CheckBox
{widgetType: ccui.CheckBox, events: ["Selected", "Unselected"]},
//ListView
{widgetType: ccui.ListView, events:["SelectedItem"]},
//Panel
{widgetType: ccui.Layout, events: sz.UILoader.touchEvents},
//BMFont
{widgetType: ccui.TextBMFont, events: sz.UILoader.touchEvents},
//last must null
null
];
sz.UILoader = cc.Class.extend({
_eventPrefix: null,
_memberPrefix: null,
/**
* 加载UI文件
* @param target将 jsonFile加载出的节点绑定到的目标
* @param jsonFile cocostudio UI编辑器生成的json文件
*/
widgetFromJsonFile: function(target, jsonFile, options) {
cc.assert(target && jsonFile);
if (!options) {
options = {};
}
this._eventPrefix = options.eventPrefix || sz.UILoader.DEFAULT_EVENT_PREFIX;
this._memberPrefix = options.memberPrefix || sz.UILoader.DEFAULT_MEMBER_PREFIX;
var rootNode = ccs.uiReader.widgetFromJsonFile(jsonFile);
if (!rootNode) {
cc.log("Load json file failed");
}
target.rootNode = rootNode;
target.addChild(rootNode);
this._bindMenbers(rootNode, target);
},
/**
* 递归对rootWidget下的子节点进行成员绑定
* @param rootWidget
* @param target
* @private
*/
_bindMenbers: function(rootWidget, target) {
var widgetName,
children = rootWidget.getChildren();
var self = this;
children.forEach(function(widget) {
widgetName = widget.getName();
//控件名存在,绑定到target上
var prefix = widgetName.substr(0, self._memberPrefix.length);
if (prefix === self._memberPrefix) {
target[widgetName] = widget;
self._registerWidgetEvent(target, widget);
}
//绑定子控件,可以实现: a._b._c._d 访问子控件
if (!rootWidget[widgetName]) {
rootWidget[widgetName] = widget;
}
//如果还有子节点,递归进去
if (widget.getChildrenCount()) {
self._bindMenbers(widget, target);
}
});
},
/**
* 获取控件事件
* @param widget
* @returns {*}
*/
_getWidgetEvent: function(widget) {
var bindWidgetEvent = null;
var events = sz.UILoader.widgetEvents;
for (var i = 0; i < events.length; i++) {
bindWidgetEvent = events[i];
if (widget instanceof bindWidgetEvent.widgetType) {
break;
}
}
return bindWidgetEvent;
},
/**
* 注册控件事件
* @param target
* @param widget
* @private
*/
_registerWidgetEvent: function(target, widget) {
var name = widget.getName();
//截取前缀,首字母大写
var newName = name[this._memberPrefix.length].toUpperCase() + name.slice(this._memberPrefix.length + 1);
var eventName = this._eventPrefix + newName + "Event";
var isBindEvent = false;
if (target[eventName]) {
isBindEvent = true;
} else {
//取事控件件名
var widgetEvent = this._getWidgetEvent(widget);
if (!widgetEvent) {
return;
}
//检查事函数,生成事件名数组
var eventNameArray = [];
for (var i = 0; i < widgetEvent.events.length; i++) {
eventName = this._eventPrefix + newName + widgetEvent.events[i];
eventNameArray.push(eventName);
if (cc.isFunction(target[eventName])) {
isBindEvent = true;
}
}
}
//事件响应函数
var self = this;
var eventFunc = function(sender, type) {
var callBack;
if (eventNameArray) {
var funcName = eventNameArray[type];
callBack = target[funcName];
} else {
callBack = target[eventName];
}
if (self._onWidgetEvent) {
self._onWidgetEvent(sender, type);
}
if (callBack) {
return callBack.call(target, sender, type);
}
};
//注册事件监听
if (isBindEvent) {
widget.setTouchEnabled(true);
if (widget.addEventListener) {
widget.addEventListener(eventFunc, target);
} else {
widget.addTouchEventListener(eventFunc, target);
}
}
}
});
sz.uiloader = new sz.UILoader();
GameLayer = cc.Layer.extend({
ctor: function() {
this._super();
//加载UI文件,绑定控件和事件到this
sz.uiloader.widgetFromJsonFile(this, "res/DemoLogin.ExportJson");
//立即可以访问控件的属性方法了
cc.log(this._closeButton.getName());
},
/*
* _closeButton的TouchBegan事件处理函数
*/
_onCloseButtonTouchBegan: function(sender) {
cc.log("_onCloseButtonTouchBegan");
},
});
sz.uiloader.widgetFromJsonFile(this, "res/DemoLogin.ExportJson", {eventPerfix:"on", memberPrefix:"m_"} );
最后一个可选参数options对象,有两个属性
eventPerfix 、memberPrefix用于配置事件前缀和成员变量前缀
_onLoginButtonEvent: function(sender, type) {
switch (type) {
case 0:
cc.log("_onLoginButtonEvent: began");
break;
case 1:
cc.log("_onLoginButtonEvent: move");
break;
case 2:
cc.log("_onLoginButtonEvent: end");
break;
}
},