Cocos Creator 3.6安卓端获取虚拟键盘高度问题求助
安卓端Cocos Creator 3.6获取虚拟键盘高度的正确实现方案
问题分析
你现有代码的核心问题:
- 错误选择了监听视图(窗口rootView而非Cocos的GLSurfaceView),
adjustResize实际作用于Cocos的游戏渲染视图,而非整个窗口的根视图 - 未处理监听器重复注册问题,且未过滤无效的高度触发值
- 键盘弹出前注册监听器,导致首次回调无法捕获键盘弹出后的布局变化
正确实现步骤
1. 确认Activity配置
确保AndroidManifest.xml中Activity的windowSoftInputMode仅设置adjustResize,不要叠加adjustPan:
android:windowSoftInputMode="adjustResize"
2. 原生安卓端(AppActivity.java)代码修改
替换原有键盘高度计算逻辑,直接监听Cocos的GLSurfaceView布局变化,并处理回调过滤与内存泄漏:
import android.graphics.Rect; import android.util.DisplayMetrics; import android.view.View; import android.view.ViewTreeObserver; import android.content.res.Resources; import org.cocos2dx.lib.CocosHelper; import org.cocos2dx.lib.CocosJavascriptJavaBridge; import org.cocos2dx.lib.Cocos2dxGLSurfaceView; public class AppActivity extends org.cocos2dx.lib.Cocos2dxActivity { private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener; private int lastKeyboardHeight = 0; // 供Cocos JS调用的注册方法 public void registerKeyboardHeightListener() { // 先移除旧监听器,避免重复注册 if (keyboardLayoutListener != null) { getGLSurfaceView().getViewTreeObserver().removeOnGlobalLayoutListener(keyboardLayoutListener); } keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Rect visibleFrame = new Rect(); // 监听Cocos渲染视图的可见区域变化 getGLSurfaceView().getWindowVisibleDisplayFrame(visibleFrame); // 获取屏幕真实高度(含状态栏、导航栏) DisplayMetrics displayMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics); int screenFullHeight = displayMetrics.heightPixels; // 计算键盘高度:减去可见区域底部、导航栏高度 int navigationBarHeight = getNavigationBarHeight(); int keyboardHeight = screenFullHeight - visibleFrame.bottom - navigationBarHeight; // 过滤无效触发:高度差超过50才通知,避免微小布局波动 if (Math.abs(keyboardHeight - lastKeyboardHeight) > 50) { lastKeyboardHeight = keyboardHeight; // 通知Cocos JS层 notifyCocosKeyboardHeight(Math.max(keyboardHeight, 0)); } } }; // 绑定监听器到Cocos视图 getGLSurfaceView().getViewTreeObserver().addOnGlobalLayoutListener(keyboardLayoutListener); } // 获取系统导航栏高度 private int getNavigationBarHeight() { Resources res = getResources(); int resId = res.getIdentifier("navigation_bar_height", "dimen", "android"); return resId > 0 ? res.getDimensionPixelSize(resId) : 0; } // 向Cocos JS层传递键盘高度 private void notifyCocosKeyboardHeight(final int height) { CocosHelper.runOnGameThread(new Runnable() { @Override public void run() { // 调用JS全局回调方法 String jsCmd = String.format("window.onKeyboardHeightChanged(%d)", height); CocosJavascriptJavaBridge.evalString(jsCmd); } }); } // 页面销毁时清理监听器,防止内存泄漏 @Override protected void onDestroy() { super.onDestroy(); if (keyboardLayoutListener != null) { getGLSurfaceView().getViewTreeObserver().removeOnGlobalLayoutListener(keyboardLayoutListener); keyboardLayoutListener = null; } } }
3. Cocos Creator JS层代码修改
注册全局回调,并在输入框编辑开始时触发原生监听器注册:
import { _decorator, Node, sys, native, Component } from 'cc'; const { ccclass, property } = _decorator; @ccclass('InputManager') export class InputManager extends Component { @property(Node) inputNode: Node = null; // 你的输入框节点 onLoad() { // 注册全局键盘高度回调 window['onKeyboardHeightChanged'] = (height: number) => { this.adjustInputPosition(height); }; } // 输入框编辑开始事件绑定的方法 onInputStart() { if (sys.isNative && sys.os === sys.OS.ANDROID) { // 调用原生注册监听器 native.reflection.callStaticMethod( "com/cocos/game/AppActivity", "registerKeyboardHeightListener", "()V" ); } } // 调整输入框位置 adjustInputPosition(keyboardHeight: number) { if (!this.inputNode) return; if (keyboardHeight > 0) { // 键盘弹出:将输入框移至键盘上方(20为间距,可根据布局调整) this.inputNode.setPositionY(keyboardHeight + 20); } else { // 键盘隐藏:恢复输入框原位置(这里假设原Y为0,根据实际布局修改) this.inputNode.setPositionY(0); } } }
关键注意点
- 必须监听Cocos的
GLSurfaceView:adjustResize仅会调整该视图的大小,而非整个窗口的根视图 - 过滤高度差:避免因状态栏、导航栏的微小变化触发无效回调
- 清理监听器:在Activity销毁时移除监听器,防止内存泄漏
- 避免
adjustPan:该属性会让窗口整体平移而非resize,导致布局变化监听失效
内容的提问来源于stack exchange,提问作者Sahana Dattatreya Hegde
相关产品推荐
相关产品推荐

