最近项目碰到一个问题,就是在按钮置灰后,按钮上的文字没有跟着置灰。经过一番研究,做出了一下处理,供大家参考一下。
首先,按钮的置灰其实是置灰的按钮上的Sprite组件,将其state设置为了cc.Sprite.State.Gray。
而实际做的事情就是加了一个置灰的shader,将颜色值设置成一个置灰后的颜色。这里我们类似的,给文字和描边也做这样的处理。
以下是置灰算法:
let gray = r * 0.299 + g * 0.587 + b * 0.114;
那么置灰后的color就是 cc.color(gray, gray, gray)。
于是我在这里重写了cc.Sprite的_activateMaterial方法,使其在设置state的时候,将其子节点的文本也置灰。具体的看代码
let _oriActivateMaterial = cc.Sprite.prototype._activateMaterial;
cc.Sprite.prototype._activateMaterial=function() {
_oriActivateMaterial.apply(this);
if (!CC_EDITOR) {
//处理文本
let labelComps =this.node.getComponentsInChildren(cc.Label);
for (let i =0; i < labelComps.length; i++) {
let labelComponent = labelComps[i];
labelComponent.setState(this._state);
}
//描边
let labelOutLineComps =this.node.getComponentsInChildren(cc.LabelOutline);
for (let i =0; i < labelOutLineComps.length; i++) {
let outlineComp = labelOutLineComps[i];
outlineComp.setState(this._state);
}
}
};
这里我为以上两个组件增加了setState方法。看代码:
cc.Label原型修改
/**
* 用于设置文本置灰状态
*/
cc.Label.prototype._state = cc.Sprite.State.NORMAL;
cc.Label.prototype._grayColor =null;
cc.Label.prototype._color =null;
cc.Label.prototype.setState =function(state) {
if (state ===this._state)return;
this._state = state;
if (!this._color ||
(!this.node.color.equals(this._color) && !this.node.color.equals(this._grayColor))) {
this._color =this.node.color;
let _grayColor =this._color.r *0.3 +this._color.g *0.59 +this._color.b *0.11;
this._grayColor = cc.color(_grayColor, _grayColor, _grayColor);
// console.log('更新状态:', this._color.toString(), this._grayColor.toString());
}
if (state === cc.Sprite.State.GRAY) {
this.node.color =this._grayColor;
}else if (state === cc.Sprite.State.NORMAL) {
this.node.color =this._color;
}
};
cc.LabelOutLine原型修改
/**
* 用于设置文本置灰状态
*/
cc.LabelOutline.prototype._state = cc.Sprite.State.NORMAL;
//置灰后的颜色值
cc.LabelOutline.prototype._grayColor =null;
//原颜色值
cc.LabelOutline.prototype._oriColor =null;
/**
* 设置描边状态
* @param state cc.Sprite.State
*/
cc.LabelOutline.prototype.setState =function(state) {
if (state ===this._state)return;
this._state = state;
if (!this._oriColor ||
(!this._color.equals(this._oriColor) && !this._color.equals(this._grayColor))) {
this._oriColor =this._color;
let _grayColor =this._oriColor.r *0.3 +this._oriColor.g *0.59 +this._oriColor.b *0.11;
this._grayColor = cc.color(_grayColor, _grayColor, _grayColor);
// console.log('更新状态:', this._oriColor.toString(), this._grayColor.toString());
}
if (state === cc.Sprite.State.GRAY) {
this.color =this._grayColor;
}else if (state === cc.Sprite.State.NORMAL) {
this.color =this._oriColor;
}
};
这样就完成了置灰效果。
有一点需要注意的是,我还修改了cc.Color的equals方法,不然上述equals会不相等
/**
* 颜色相同也视为相同
* @param other
* @returns {boolean}
*/
cc.Color.prototype.equals =function(other) {
if (other &&this._val == other._val) {
return true;
}
if (this.getR() == other.getR() &&this.getB() == other.getB()
&&this.getG() == other.getG() &&this.getA() == other.getA()){
return true;
}
return false;
}
总结一下,就是在按钮精灵state改变时,同时改变其子节点里文本和描边组件的颜色。如果想置灰其它组件,也同理了。