API 场景:#Activity \ #AlertDialog \ #PopupWindow \ ...
getWindow().setSoftInputMode(int flag {@link WindowManager.LayoutParams.#softInputMode));
1.SOFT_INPUT_ADJUST_PAN
系统会选择一种合理的方式平移window,使得获取焦点的输入框可见,不会改变布局大小。
2.SOFT_INPUT_ADJUST_RESIZE
软键盘弹出时window大小可被调整,使得可见内容不被覆盖,该属性与SOFT_INPUT_ADJUST_PAN互斥,不能同时使用。
注:API中指出,window添加属性中存在 {@link #WindowManager.LayoutParams.# FLAG_FULLSCREEN}情况,
系统会忽略SOFT_INPUT_ADJUST_RESIZE属性,解决方案见下文。
3.SOFT_INPUT_ADJUST_NOTHING
软键盘弹出时window不被平移也不会改变大小。
4.SOFT_INPUT_ADJUST_UNSPECIFIED
系统会根据window内容选择一种显示方式,一般不推荐,不同的Android版本可能存在差异,会导致页面兼容性问题。
2.问题场景 & 解决方案
1.Android文本可编辑控件<EditText>场景,例如 评论、登录、个人中心 ...
推荐使用# SOFT_INPUT_ADJUST_PAN模式,系统根据当前焦点文本框的位置平移window,交互体验较好。
2.WebView应用场景
- a. WebView场景中由Android文本编辑控件<EditText>触发软键盘,此时与场景1没有区别,使用#SOFT_INPUT_ADJUST_PAN模式;
- b. WebView场景中由H5元素触发软键盘,此时使用#SOFT_INPUT_ADJUST_RESIZE模式,使得window改变大小,保证WebView内容不被遮挡。
3.全屏窗口使用场景<#FLAG_FULLSCREEN>
FULLSCREEN效果是全屏显示(SystemUI StatusBar 会被置于底层,activity的window置于上层),此时如果涉及软键盘弹出遮挡问题则不能使用SOFT_INPUT_ADJUST_RESIZE方式开解决。
3. 轻框 webview 解决方案
3.1 背景:
目前线上 webview 里的 H5 点击输入框没有反应,因为webview被放在全屏模式下了。但是你也不可能去更改模式,这样影响会比较大。目前就是需要在保证业务逻辑不受影响的情况下去,如何让轻框弹出软键盘。
3.2 解决方案:
百度一搜会发现很多webview都出现了类似问题,但是最早的问题可以见 WebView adjustResize windowSoftInputMode breaks when activity is fullscreen 一文,这是开发者最早在 android 源码上提出来的bug,不过bug级别为 P3,一直也没有给解决。
在 stackoverflow 上也有用户提出了问题,Android How to adjust layout in Full Screen Mode when softkeyboard is visible,文章后面有人给出了答案:

public class AndroidBug5497Workaround {
// For more information, see https://issuetracker.google.com/issues/36911528
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
public static void assistActivity (Activity activity) {
new AndroidBug5497Workaround(activity);
}
private View mChildOfContent;
private int usableHeightPrevious;
private FrameLayout.LayoutParams frameLayoutParams;
private AndroidBug5497Workaround(Activity activity) {
FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
mChildOfContent = content.getChildAt(0);
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
possiblyResizeChildOfContent();
}
});
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
}
private void possiblyResizeChildOfContent() {
int usableHeightNow = computeUsableHeight();
if (usableHeightNow != usableHeightPrevious) {
int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
if (heightDifference > (usableHeightSansKeyboard/4)) {
// keyboard probably just became visible
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
} else {
// keyboard probably just became hidden
frameLayoutParams.height = usableHeightSansKeyboard;
}
mChildOfContent.requestLayout();
usableHeightPrevious = usableHeightNow;
}
}
private int computeUsableHeight() {
Rect r = new Rect();
mChildOfContent.getWindowVisibleDisplayFrame(r);
return (r.bottom - r.top);
}
}

使用方式是在对应的 activity 页面的 onCreate 中进行调用即可:
AndroidBug5497Workaround.assistActivity(this);
3.3 方案应用
看到解决方案后,内心狂喜,就这么简单啊。开心的将其copy到项目中,编译,安装,启动。打开用轻框承载的页面,激动的点下,键盘弹起来了。哇塞,问题解决了。多次几次后发现还是存在一些问题:
- 键盘弹起后,落下的时候,可以见到底部有一块黑色阴影,这个是很影响用户体验的;
3.4 完善方案
问题1
针对3.3中的问题1,猜测是失去焦点了,导致没有把焦点的 view 平移出来。可是为啥有时候有问题,有时候没问题呢,不觉得这个是很诡异的事情吗?
于是又开始疯狂百度和Google,结果发现竟然没有人跟我有一样的遭遇。这,为何只有我需要承受这种伤害。最终在经历了两天多的各种尝试和自我怀疑后,突然想到我现在使用的是T7内核,那我如果不使用呢?很快,我在 debug 模式下禁用了 T7 内核,使用原生内核,在尝试后,竟然没有问题了,喜大普奔啊。于是,我将问题反馈给内核同学,后来内核同学发现代码在处理焦点逻辑的时候存在问题,但是具体解决方案短期还是无法给出。
问题2
针对3.3中的问题2,之所以会出现黑色背景,是因为我们将 contentview 的大小给改变了,导致漏出来的黑色背景。解决这个问题有两种方式
- 一种是设置背景颜色,但是这样的话,代码使用上有点打折扣。
- 另一种方案是只改变 webview 外层容器 container 的高度,这样即使container高度变了, 还是有背景的。
问题3
其实这个问题跟问题2的第二种解法类似,就是改变 webview 外层容器 container 的高度,不要去更改包含返回条的view即可;
问题4
解决上述三个问题后,提测。
QA测试中又发现一个新的问题,在部分屏幕高度有限的手机中,底部的举报按钮被返回条遮挡了,但是无法滑动。
如上图所示,可以看到底部的提交按钮被返回条遮挡了,并且页面不能滑动。
那么页面为啥不能滑动了呢?
原因:当你用网上给的解决方案修改内层view的时候,最后是将当前window的可见高度赋给了内层view,这个高度和其原始高度并不一定是相等的。当你多给了一些高度,会让原本不可见的内容变成了可见,于是view就变成不可滑动的呢。
解决这个问题的方案也很简单,那就是恢复其原来的高度。
- 第一种修复方案是,当键盘收起之后,将 view 的高度变成 ViewGroup.LayoutParams.MATCH_PARENT,这时候会触发重新测量等逻辑。
frameLayoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
但是这种方案不推荐就是这么改可能会导致绘制次数变多,影响页面性能;
2、第二种修复方案是,在键盘弹起的时候,记录此时需要改变的 container 的高度,在键盘收起后,恢复原始高度即可。
到这里,应该是比较完美了。
但是这里还有个问题,就是他会监听每次绘制,然后触发再次绘制,可能会导致线上绘制次数变多。好的办法就是只有在键盘弹起和收起之间去做这个操作。

/** 屏幕高度比例,0.85来源{@link AbsBdFrameView} */
private static final float RATE = 0.85f;
/** 上一次的可见高度 */
private int mLastVisibleHeight;
/** 保存视图键盘未弹出时高度值 */
private int mViewHeight;
/** 布局参数 */
private ViewGroup.LayoutParams mParams;
/** OnGlobalLayoutListener */
private ViewTreeObserver.OnGlobalLayoutListener mOnGlobalLayoutListener;
/** rootView */
private ViewGroup mRootView;
/** Resume 生命周期状态码 */
private boolean mIsResuming;
public KeyBoardWorkaround(@NonNull ViewGroup rootView) {
mRootView = rootView;
addOnGlobalLayoutListener();
}
/**
* 添加layout回调
*/
private void addOnGlobalLayoutListener() {
mOnGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
resizeRootView();
}
};
mRootView.getViewTreeObserver().addOnGlobalLayoutListener(mOnGlobalLayoutListener);
mParams = mRootView.getLayoutParams();
}
/**
* 调整rootView的大小
*/
private void resizeRootView() {
// 屏幕的高度 * 0.85得到一个处于输入法弹起后页面可见的高度(0.85来源{@link AbsBdFrameView})
int hasKeyboardHeight = (int) (DeviceUtils.ScreenInfo.getRealScreenHeight(mRootView.getContext()) * RATE);
// webView + 输入法的状态下,保证恢复高度的layout不会被过滤掉而出现白屏问题{@link AbsBdFrameView}
if (mLastVisibleHeight >= hasKeyboardHeight && !mIsResuming) {
return;
}
Rect r = new Rect();
// 这里获取的是window的可见高度,而不是mRootView的可见高度
mRootView.getWindowVisibleDisplayFrame(r);
int displayHeight = r.bottom - r.top;
int rootViewHeight = mRootView.getHeight();
// view可见高度&尺寸均大于键盘弹出时的高度,说明此时无键盘弹出和收起情况,直接返回
if (Math.min(displayHeight, rootViewHeight) > hasKeyboardHeight) {
return;
}
// 键盘状态变更
if (displayHeight != rootViewHeight && displayHeight > 0 && rootViewHeight > 0) {
// 该条件为true时表示键盘弹出
if (displayHeight < hasKeyboardHeight) {
mParams.height = displayHeight;
// 记录view原始高度
mViewHeight = rootViewHeight;
} else {
mParams.height = mViewHeight;
}
mLastVisibleHeight = mParams.height;
mRootView.requestLayout();
}
}

到这里,关于webview软键盘的问题就解决了。方案经过多次优化后,已经变得比较完美了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)