cocos input在android 半身webview不能顶起页面问题

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

预格式化文本将缩进 4 格

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();
}

}