大家好,分享一個我們最近排查到的 Android Chrome 橫直切換問題。
環境是:
LayaAir 3.3.10
scaleMode = showall
Android Chrome
iOS Safari 未重現
現象是:手機直版切橫版時,偶爾 canvas/stage 沒有正確貼合實際可視區,導致遊戲畫面底部被瀏覽器窗口切掉。點一下畫面後通常又會恢復正常。
一開始我們以為是遊戲內 UI transition 或橫直版 layout 動畫問題,後來做了一個乾淨場景,只建立一個 Maingame Sprite,不跑遊戲 UI transition,依然可以重現,所以基本排除遊戲 UI layout。
關鍵 log 如下:
window.innerWidth / innerHeight = 592 x 328
visualViewport.width / height = 592 x 280
canvas rect = 583 x 328
也就是 Android Chrome 旋轉時,window.innerHeight 已經回報 328,但 visualViewport.height 還是 280,實際可見區也像是 280。Laya 的 showall resize 如果用到 328,就會把 canvas 撐到 328 高,結果底部 48px 被切掉。
我們目前的 workaround 是:
Android landscape 時,如果偵測到 visualViewport.height 明顯小於 window.innerHeight,先記住這個較小的安全高度。
在一段保守時間內,不要立刻相信後續變大的 window.innerHeight。
不只呼叫 updateCanvasSize(),而是直接用安全高度套 stage.setScreenSize(width * pixelRatio, height * pixelRatio),避免後續 Laya resize 又把 canvas 撐回較大的尺寸。
退出橫版或進 fullscreen 後再釋放這個保守高度。
簡化概念大概是:
const vv = window.visualViewport;
const dpr = Laya.Browser.pixelRatio window.devicePixelRatio 1;
if (Laya.Browser.onAndroid && vv && isLandscape()) {
const visualH = Math.round(vv.height);
const windowH = Math.round(window.innerHeight);
if (windowH - visualH >= 16) {
const safeW = Math.round(Math.min(window.innerWidth, vv.width));
const safeH = visualH;
const stage = Laya.stage as any;
Laya.systemTimer.clearCallLater(stage, stage.updateCanvasSize);
stage.setScreenSize?.(
Math.round(safeW * dpr),
Math.round(safeH * dpr)
);
}
}
目前我們測了幾十次 Android 旋轉,暫時沒有再遇到畫面被切。
想問問大家:
LayaAir 這邊是否有更官方的「旋轉後強制刷新 stage/canvas size」方式?或者是否有人也遇過 Android Chrome visualViewport / innerHeight 在 orientationchange 後不同步,導致 showall canvas 被裁切的情況?
以上為codex排查之結論,不代表本人立場. 嘿嘿