CocosCreator上实现自定义字体的输入框

  • Post author:
  • Post category:其他


目前CocosCreator的最新版本2.0.4提供的输入框组件cc.EditBox没有自定义字体的功能,而且文字也不能居中显示,为了实现这些功能,可以在cc.EditBox的基础上再包装一层,把原本cc.EditBox的文字隐藏,在其上方放置一个文本标签,通过监听cc.EditBox的输入事件来设置文本标签的内容。而文本标签cc.Label是可以设置字体以及实现对齐方式的,故而可以此来实现输入框的这些效果。



下载

  • 要预览输入框效果,可点击

    效果样例

    ,下载后用CocosCreator打开运行。
  • 本人写的

    输入框脚本组件

    ,下载后即可挂载到某个节点上即可使用,可在编辑器下运行。功能不完善,可能有bug,请指正。



实现

下面介绍一下主要的实现过程。



隐藏原本的cc.EditBox

新的输入框的实现借助了cc.EditBox的输入事件,而它原本显示的文本我们要隐藏掉,以便在那个位置上显示我们自己的文本标签。为了隐藏掉cc.EditBox的文本,本人试过了很多方法,把其所在节点active设置false虽然可以隐藏但输入框也无法响应操作了,自然不可行;透明度设为0或是把其放置到背景下层,输入的时候文字还是会浮现在最上层(后查知这似乎是与CocosCreator原生组件永远最后渲染有关);最后发现把其节点的高度设置为0就能实现文字的隐藏,但这样的话将无法点击到输入框,即无法开始输入。



点击开始输入

为了实现可以点击开始输入,查阅文档得知cc.EditBox有一个方法setFocus()。

setFocus

让当前 EditBox 获得焦点

当用户点击当前节点后调用这个方法可以强行开始输入,在手机端弹出键盘。

在CustomEditBox.js的onLoad中写入以下代码,以创建带cc.EditBox的节点:

//创建带输入框组件的节点。弹出及收起键盘、获取输入的文字,都是通过这个组件来实现的
let nodeEditBox = new cc.Node("EditBox");
nodeEditBox.width = this.node.width;
//高度为0,以隐藏输入时显示的文字
nodeEditBox.height = 0;
this.node.addChild(nodeEditBox, 0);
//添加并设置输入框组件
let editBox = nodeEditBox.addComponent(cc.EditBox);
editBox.inputMode = cc.EditBox.InputMode.SINGLE_LINE;
editBox.maxLength = this.maxLength;

然后监听触摸结束事件,在回调函数中调用setFocus开始输入。此时只能监听触摸结束事件,因为如果在触摸开始或触摸移动中调用setFocus,接下来一定触发触摸结束事件,而触摸结束事件触发时会使输入框失去焦点而使得输入结束,最终导致点击开始输入后立即就结束了。

//监听cc.EditBox组件产生的事件,以实现变更输入文字,结束输入的操作
this.node.on("touchend", () => {
    this._startEdit();
});


创建显示输入文字的节点

首先在脚本文件的properties字段中声明一个字体资源的属性,以便用户可以在编辑器中拖拽字体资源来设置字体。

font: {
    displayName: "字体",
    type: cc.Font,
    default: null,
    //设置notify以在编辑器中实时预览设置效果
    notify: function () {
    	if (this.node) {
    		//获取文字显示节点的Label组件并设置其字体
    		this.node.getChildByName("Text").getComponent(cc.Label).font = this.font;
    	}
    }
}

关于更多的属性声明的内容可以参阅

CocosCreator脚本属性在属性面板的显示

//创建文本显示节点。显示在输入框输入的文字,通过读取cc.EditBox组件的文字来更新自身文字内容
let nodeText = this.node.getChildByName("Text");
if (!nodeText) {    //获取并判断名为Text的子节点是否存在是为了编辑器中不重复创建节点
    nodeText = new cc.Node("Text");
    this.node.addChild(nodeText, 1);
    //添加并设置Label组件
    let label = nodeText.addComponent(cc.Label);
    //设置字体
    if (this.font) {
        label.font = this.font;
    }
}

有了显示输入内容的节点,就可以在点击开始输入时显示闪烁的光标,以提示用户可以开始输入了。



光标闪烁

为了实现在脚本的onLoad中创建光标,而不依赖任何外部图像资源,且要与字体颜色保持一致,可以创建一个Label的节点,其文字设置为一个特殊字符: █,即完全填充一个字符位置的色块。然后设置Label组件的overflow为

CLAMP

,节点宽度为1。这样文字被截成宽度为1,高度为行高的字符,正好可以用来做光标。

而光标闪烁实现可以在脚本文件的update中更新光标节点的可见性。

ctor() {
    //光标节点的引用
    this._cursor = null;
    //标记当前是否处于编辑状态
    this._isEditing = false;
    //实现光标闪烁所需的计时器
    this._blinkTimer = 0;
}//每帧更新光标的状态
update(dt) {
    if (!CC_EDITOR) {    //编辑器下不更新光标
        this._updateCursor(dt);
    }
}//实现光标闪烁
_updateCursor(dt) {
    if (!this._isEditing) {    //不是编辑状态
        this._cursor.active = false;
        return;
    }

    if (this._blinkTimer >= 0.5) {    //计时器运行了0.5秒
    	//重置计时器
        this._blinkTimer = 0;
        //反转光标节点可见性
        this._cursor.active = !this._cursor.active;
    } else {    //计时器还没到0.5秒
    	//计时器增加两帧之间的时间间隔
        this._blinkTimer += dt;
    }
}


显示正在输入的文字

通过监听cc.EditBox的节点上的text-changed事件,可在输入文字改变时获取cc.EditBox的文字,以此来更新显示出来的文字。

//this._editBox为cc.EditBox的引用
this._editBox.node.on("text-changed", () => {
		//this._labelText为用于显示文字的Label组件的引用
    	this._labelText.string = this._editBox.string;
    }
});

至此,CustomEditBox已经可以实现点击开始输入文字,光标闪动,按下键盘可以看到输入文字的增加,但还没实现结束输入。结束输入可以监听上面代码中的this._editBox的editing-did-ended事件,在事件回调中隐藏光标,即表示结束输入了。

Android平台和微信小游戏平台会出现点击输入框之外无法结束输入,翻阅Cocos文档并没有发现可以主动失去焦点的API,故这个问题还没有很优雅的解决方案。



版权声明:本文为SitToSeeBloomFade原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。