场景1
问题描述
常规的,当点击EditText
输入框时,软键盘弹出,但键盘会遮挡EditText
显示。
解决方案
AndroidManifest
文件中,Activity新增配置android:windowSoftInputMode
,设置值为adjustPan
或adjustResize
,如下:
<activity
android:name="xxx"
android:windowSoftInputMode="adjustPan" />
adjustPan和 adjustResize的区别
-
adjustPan
配置该参数,整个界面会向上平移,显示输入框,但不改变界面的布局。 -
adjustResize
配置该参数,系统会重新计算除去软键盘后的界面尺寸,用更少的界面区域显示内容,输入框也在其中。
场景2
问题描述
混合开发中,应用在非全屏模式下,WebView
加载网页,点击输入框,软键盘遮挡问题。
解决方案
操作方法同上,但是只支持设置值为adjustResize
,设置 adjustPan
无效。
场景3
问题描述
- 混合开发中,应用在全屏模式下(Application或activity使用Fullscreen主题、沉浸式状态栏、
Immersive Mode
等),WebView加载网页,点击输入框,软键盘遮挡问题。 -
android:windowSoftInputMode
设置值为adjustPan
或adjustResize
均无效。 - 这是系统级别的一个坑。
解决方案
方案1
当一个Activity
中包含WebView
控件时,尽量避免使用全景模式。(当然这个方法治标不治本)
方案2
stackflow
上有个大牛提供了解决方案。(stackflow地址)
具体代码如下,
import android.app.Activity;
import android.graphics.Rect;
import android.os.Build;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
/**
* 修复WebView全屏模式下,软键盘遮挡问题
*/
public final class AndroidBug5497Workaround {
private View mChildOfContent;
private int usableHeightPrevious;
private FrameLayout.LayoutParams frameLayoutParams;
private int contentHeight;
private boolean isFirst = true;
private int statusBarHeight;
public static void assistActivity(Activity activity) {
new AndroidBug5497Workaround(activity);
}
private AndroidBug5497Workaround(Activity activity) {
//获取状态栏的高度
int resourceId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
statusBarHeight = activity.getResources().getDimensionPixelSize(resourceId);
FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
mChildOfContent = content.getChildAt(0);
//界面出现变动都会调用这个监听事件
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
if (isFirst) {
contentHeight = mChildOfContent.getHeight();//兼容华为等机型
isFirst = false;
}
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)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference + statusBarHeight;
} else {
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
}
} else {
frameLayoutParams.height = contentHeight;
}
mChildOfContent.requestLayout();
usableHeightPrevious = usableHeightNow;
}
}
/**
* 计算mChildOfContent可见高度
*
* @return
*/
private int computeUsableHeight() {
Rect r = new Rect();
mChildOfContent.getWindowVisibleDisplayFrame(r);
return (r.bottom - r.top);
}
}
- 将该类新增到项目中,并在对应
Activity
的onCreate()
方法中调用即可。
AndroidBug5497Workaround.assistActivity(this);
AndroidBug5497Workaround
类解析:
通过
findViewById(android.R.id.content)
获取Activity界面开发者可控区域的根View。(全屏模式下,即为全部屏幕区域,非全屏模式下为除状态栏外区域)mChildOfContent = content.getChildAt(0);
,获取Activity
布局的View
(即通过setContentView()
设置的View
)。View.getViewTreeObserver()
获取一个专门监听当前View树变化的观察者对象。由于软键盘的弹出,会使View树的全局布局(GlobalLayout)发生变化,所以给当前View树变化的观察者对象绑定监听
addOnGlobalLayoutListener
。一旦触发
addOnGlobalLayoutListener
监听,主要则是调用possiblyResizeChildOfContent()
方法,重置界面变化后可用区域。possiblyResizeChildOfContent()
方法中,heightDifference > (usableHeightSansKeyboard / 4)
这个判断只有界面的高度变化超过1/4,才重置高度,确保响应软键盘的弹出,排除其他界面变化情况,computeUsableHeight()
则是计算除去键盘后重新调整布局的可用高度。
软键盘遮挡界面问题总结
Android输入框软键盘遮挡问题,通常有以下三种情况:
在无WebView的界面下:
按需求配置android:windowSoftInputMode
,为adjustPan
或adjustResize
。有WebView的界面下:
非全屏模式:
配置android:windowSoftInputMode
为adjustResize
。
全屏模式:
项目新增一个AndroidBug5497Workaround
类,完美解决。