1:场景:游戏嵌入到android平台的webview(非全屏模式),cocos creator 引擎版本:2.3.1
2:问题:
a: 用到了输入框组件但是输入框聚焦用问题,cocos的editorBegin触发的不对,有时候editorBegin触发了但是键盘没有弹出来,很坑,不能忍,产品的需求是当键盘出来的时候抬高输入框尴尬的就是这点(我依据的是只要editorBegin方法触发我就抬高输入框)
b: 顶不起游戏页面,输入框被键盘遮挡,暂且还能忍
我起先是用html5的input代替,但是发现用百分比适配是有问题的,于是我转头去看cocoscreator的input实现,发现input框是依附到cocos节点上进行适配的,利用css的transform的matrix转换,于是自己定义了一个输入框组件,实现跟cocos的edtiroBox差不多,实现了updateMatrix方法,聚焦问题解决了,聚焦的时候一定会弹出键盘,聚焦的时候我抬高input依附的节点,更新input的位置,但是问题是在某些手机上输入框没有抬起,但是节点的位置实际上是已经抬起了的,不知道哪里的问题了哈哈:
具体实现:myInput.ts
const {ccclass, property,executeInEditMode} = cc._decorator;
/**
*
* 输入框组件 原生html标签需要依附一个 ccc节点 设置位置信息
*
*/
let polyfill = {
zoomInvalid: false
};
@ccclass
// @executeInEditMode
export default class MyInput extends cc.Component {
@property(cc.EditBox)
cocosBox: cc.EditBox = null;
@property(cc.Float)
fontSize: number = 20;
/** input框html元素 */
public inputElement: HTMLInputElement = null;
public worldMat = new cc.Mat4();
public cameraMat = new cc.Mat4();
private vec: cc.Vec3 = cc.v3();
private _m00 = 0;
private _m01 = 0;
private _m04 = 0;
private _m05 = 0;
private _m12 = 0;
private _m13 = 0;
private _w = 0;
private _h = 0;
private _isShow: boolean = true;
private _cacheViewportRect = cc.rect(0,0,0,0);
/**
* 是否显示输入框
* @param {boolean} tag
*/
public set isShow(tag: boolean) {
if(!this.inputElement) {
console.log('输入框为空');
return;
}
this._isShow = tag;
if(tag) {
this.inputElement.style.display = '';
this.inputElement.style.opacity = '1';
} else {
this.inputElement.style.display = 'none';
this.inputElement.style.opacity = '0';
}
}
public get isShow() {
return this._isShow;
}
onLoad () {
const container = cc.game.container;
this.inputElement = document.createElement("input");
this.inputElement.style.border = "1px solid black";
this.inputElement.style.borderRadius = "100px";
this.inputElement.style.background = 'transparent';
this.inputElement.style.width = this.node.width + 'px';
this.inputElement.style.height = this.node.height + 'px';
// this.inputElement.style.active = ;
this.inputElement.style.outline = 'medium';
this.inputElement.style.padding = '10px 10px';
this.inputElement.style.textTransform = 'uppercase';
this.inputElement.style.position = "absolute";
this.inputElement.style.bottom = "0px";
this.inputElement.style.left = 1 + "px";
this.inputElement.className = "myInput";
this.inputElement.id = 'myInput0';
this.inputElement.style.background = '#ffffff';
this.inputElement.style.fontSize = this.fontSize + 'px';
this.inputElement.placeholder = "请输入你的答案"
container.appendChild(this.inputElement);
if (cc.sys.OS_ANDROID === cc.sys.os &&
(cc.sys.browserType === cc.sys.BROWSER_TYPE_SOUGOU ||
cc.sys.browserType === cc.sys.BROWSER_TYPE_360)) {
polyfill.zoomInvalid = true;
}
this.inputElement.onfocus = () => {
console.log('focus',cc.view.getViewportRect());
if(cc.sys.isBrowser && cc.sys.os === cc.sys.OS_IOS) {
return;
}
this.node.y = 180;
console.log('nodey is ',this.node.y);
// console.log(this.cocosBox._impl._elem);
// this.cocosBox.editBoxEditingDidBegan();
this.scheduleOnce(() => {
this.updateMatrix();
console.log('viewport is ',cc.view.getViewportRect());
},0)
}
this.inputElement.oninput = (data: any) => {
console.log('input',data.data,this.node.y);
if(this.node.y !== 180) {
this.node.y = 180;
}
}
this.inputElement.onchange = (event: Event) => {
console.log('change',event);
const targetEvent = event.target;
console.log('value is ',targetEvent['value']);
}
this.inputElement.onblur = () => {
console.log('失去焦点',cc.view.getViewportRect());
const value = this.inputElement.value;
this.node.y = -240;
this.scheduleOnce(() => {
this.updateMatrix();
console.log('失去焦点:',cc.view.getViewportRect());
},0)
if(!value.trim()) {
return;
}
this.sendBarrageData(value);
this.inputElement.value = '';
}
this.inputElement.onkeydown = (event) => {
console.log('key is ',event['key']);
if(event['key'] && event['key'] === 'Enter') {
// 软键盘的回车键
this.inputElement.blur();
this.node.y = -240;
recoverInput();
if(!this.inputElement.value.trim()) {
return;
}
this.sendBarrageData(this.inputElement.value);
}
}
this.inputElement.onsubmit = () => {
recoverInput();
}
this.inputElement.addEventListener('compositionstart',() => {
console.log('compost start');
});
this.inputElement.addEventListener('compositionend',() => {
this.node.y = -240;
this.inputElement.blur();
console.log('。。发送');
});
this.inputElement.addEventListener('touchstart',() => {
console.log('touchstart');
});
document.addEventListener('touchstart',() => {
console.log('document start');
})
const recoverInput = () => {
}
// 监听键盘是弹起还是收起不起作用
var originalHeight=document.documentElement.clientHeight || document.body.clientHeight;
window.onresize = function(){
//键盘弹起与隐藏都会引起窗口的高度发生变化
var resizeHeight=document.documentElement.clientHeight || document.body.clientHeight;
if(resizeHeight < originalHeight){
console.log('---键盘弹起');
}else{
console.log('--键盘收起');
}
}
// this.isShow = false;
this.test();
}
test() {
const mat = cc.mat4();
this.node.getWorldMatrix(mat);
console.log('mat is ',mat);
let vec = cc.v3(0,0,0);
let _w = this.node.getContentSize().width;
let _h = this.node.getContentSize().height;
vec.x = -this.node.getAnchorPoint().x * _w;
//@ts-ignore
vec.y = -this.node.getAnchorPoint().y * _h;
// vec 该节点的左下角 对世界矩阵进行变换
cc.Mat4.transform(mat,mat,vec);
console.log('vec is ',vec);
console.log('mat is ',mat);
let cameraMat;
let camera = cc.Camera.findCamera(this.node);
// camera.getWorldToScreenMatrix2D(cameraMat);
// console.log("cameraMat is ",cameraMat);
}
protected onEnable(): void {
if(cc.sys.isBrowser && cc.sys.os === cc.sys.OS_IOS) return;
this.node.on(cc.Node.EventType.TOUCH_END,this.focusInput,this);
}
protected onDisable(): void {
if(cc.sys.isBrowser && cc.sys.os === cc.sys.OS_IOS) return;
this.node.off(cc.Node.EventType.TOUCH_END,this.focusInput,this);
}
focusInput() {
if(!this.inputElement) return;
this.inputElement.focus();
}
/**
* 发送弹幕数据
* @param {string} str 弹幕数据
*/
public sendBarrageData(str: string) {
console.log('发送数据:',str);
// httpManager.send('post',RequestUrl.ANSWER,{
// answer: str,
// game_id: facdeCenter.curGameId,
// turn_index: facdeCenter.turnIndex
// },(data: any) => {
// console.log('发送弹幕数据,响应消息: ',data);
// if(data.err_code === 89007) {
// console.log('回合不正确');
// }
// if(data.status === "OK") {
// facdeCenter.selfIsAnswerRight = data.data;
// facdeCenter.hideInput(!data.data);
// const seatComp = facdeCenter.user2SeatMap[facdeCenter.userId];
// seatComp.isAnswerRight = true;
// }
// });
}
start () {
}
// 更新输入框矩阵
updateMatrix() {
let node = this.node;
node.getWorldMatrix(this.worldMat);
let worldMat = this.worldMat;
let worldMatm = worldMat.m;
//@ts-ignore
const conSize = node._contentSize;
let container = cc.game.container;
// check whether need to update
if (this._m00 === worldMatm[0] && this._m01 === worldMatm[1] &&
this._m04 === worldMatm[4] && this._m05 === worldMatm[5] &&
this._m12 === worldMatm[12] && this._m13 === worldMatm[13] &&
this._w === conSize.width && this._h === conSize.height &&
this._cacheViewportRect.equals(cc.view._viewportRect)) {
return;
}
this._m00 = worldMatm[0];
this._m01 = worldMatm[1];
this._m04 = worldMatm[4];
this._m05 = worldMatm[5];
this._m12 = worldMatm[12];
this._m13 = worldMatm[13];
this._w = conSize.width;
this._h = conSize.height;
//@ts-ignore
this._cacheViewportRect.set(cc.view._viewportRect);
//@ts-ignore
let scaleX = cc.view._scaleX, scaleY = cc.view._scaleY,viewport = cc.view._viewportRect,dpr = cc.view._devicePixelRatio;
//@ts-ignore
this.vec.x = -node._anchorPoint.x * this._w;
//@ts-ignore
this.vec.y = -node._anchorPoint.y * this._h;
cc.Mat4.transform(worldMat,worldMat,this.vec);
let cameraMat;
let camera = cc.Camera.findCamera(node);
if(!camera) {
console.log("摄像机为null");
return;
}
camera.getWorldToScreenMatrix2D(this.cameraMat);
cameraMat = this.cameraMat;
// 摄像机移动到输入框的左下角
cc.Mat4.multiply(cameraMat,cameraMat,worldMat);
scaleX /= dpr;
scaleY /= dpr;
let cameraMatm = cameraMat.m;
let a = cameraMatm[0] * scaleX, b = cameraMatm[1], c = cameraMatm[4], d = cameraMatm[5] * scaleY;
let offsetX = container && container.style.paddingLeft && parseInt(container.style.paddingLeft);
offsetX += viewport.x / dpr;
let offsetY = container && container.style.paddingBottom && parseInt(container.style.paddingBottom);
offsetY += viewport.y / dpr;
let tx = cameraMatm[12] * scaleX + offsetX, ty = cameraMatm[13] * scaleY + offsetY;
if (polyfill.zoomInvalid) {
this.setSize(node.width * a, node.height * d);
a = 1;
d = 1;
}
let elem = this.inputElement;
let matrix = "matrix(" + a + "," + -b + "," + -c + "," + d + "," + tx + "," + -ty + ")";
if(!elem) {
console.log('elemen is null');
return;
}
elem.style['transform'] = matrix;
elem.style['-webkit-transform'] = matrix;
elem.style['transform-origin'] = '0px 100% 0px';
elem.style['-webkit-transform-origin'] = '0px 100% 0px';
}
setSize (width, height) {
let elem = this.inputElement;
elem.style.width = width + 'px';
elem.style.height = height + 'px';
}
/** 更新input框的 */
update (dt) {
if(!this.inputElement) return;
this.updateMatrix();
}
}