Android进阶之路 - 解决WebView加载H5时软键盘遮挡输入框问题

远方那座山 2024-08-20 15:03:01 阅读 63

经验总是有限的,越学越无知,总是能深刻的了解到学无止境

我遇到的这个问题,花费了好几天时间去解决,后面才发现该问题可能很早以前就存在了,而且很多人特意将其解决方式以 <code>5497-bug 命名… 不过还是有必要说一下我所遇问题和解决过程

所遇问题

项目中 WebView 加载H5正常显示,但是涉及到输入框交互时会遮挡H5输入框,无法正常顶起输入框其他端可正常在弹出键盘时顶起输入框,如IOS、或一些三方应用内

解决过程

WebView 组件换为系统提供的原始组件,未进行任何二次封装(可正常顶起输入框,但其他业务受影响,故放弃)将当前二次封装的组件剥离到外部进行测试,模拟输入框场景(无效,依旧无法正常顶起输入框)变更对应 WebView 承载 Activity(WebViewActivity)的configChanges属性(无效

<activity

android:name=".xxx.WebViewActivity"code>

android:configChanges="orientation|screenSize|keyboardHidden"code>

android:exported="false"code>

android:screenOrientation="portrait"code>

android:windowSoftInputMode="stateHidden|adjustResize" />code>

换个思想出发,假设在Android中遇到类似问题如何处理?

监听键盘弹出状态,动态在输入框下增删Holder布局(简单)监听键盘弹出状态,动态设置当前布局高度(需要细心调试)监听当前布局,查看遮挡范围是否达到设置阈值,然后变更高度,再进行绘制(当前解决方案)

解决方案

这里采用的解决方式就是获取屏幕高度后,通过动态监听被遮挡范围(键盘弹出时会遮挡显示范围),实时改变布局高度

Tip:看实现的时候发现主要用到了 WindowManager().getDefaultDisplay() ,从 Display()来看应该是一个显示类,还用了 DisplayMetricsgetRealMetricsgetMetrics ,给大家分享下这几个API的意义

Display d = activity.getWindowManager().getDefaultDisplay();

d.getMetrics() - 去除状态栏和导航栏的总高度

这个方法用于填充提供的 DisplayMetrics 对象,获取当前屏幕的度量信息它返回的屏幕尺寸通常不包括系统装饰元素(如状态栏和导航栏)所占用的空间

d.getRealMetrics() - 屏幕总高度

这个方法同样用于填充提供的 DisplayMetrics 对象,但它获取的是实际的屏幕度量信息与 getMetrics() 不同,getRealMetrics() 返回的屏幕尺寸包括了系统装饰元素所占用的空间,即它提供了整个物理屏幕的尺寸

简单来说getMetrics() 提供的是应用可用的屏幕区域的度量信息,而 getRealMetrics() 提供的是整个物理屏幕的度量信息,包括系统 UI 元素所占用的部分

copy 下方 AndroidBug5497Workaround 到项目中

package cn.com.xx;

import android.app.Activity;

import android.graphics.Rect;

import android.util.DisplayMetrics;

import android.view.Display;

import android.view.View;

import android.view.ViewTreeObserver;

import android.widget.FrameLayout;

public class AndroidBug5497Workaround {

// For more information, see https://code.google.com/p/android/issues/detail?id=5497

// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.

private Activity mActivity;

public static void assistActivity(Activity activity) {

new AndroidBug5497Workaround(activity);

}

private View mChildOfContent;

private int usableHeightPrevious;

private FrameLayout.LayoutParams frameLayoutParams;

private AndroidBug5497Workaround(Activity activity) {

this.mActivity = 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 bottomSoftKeysHeight = 0;

boolean haveSoftKey = isHaveSoftKey(mActivity);

if (haveSoftKey) {

bottomSoftKeysHeight = getBottomSoftKeysHeight(mActivity);

}

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;//之前的,因顶起太高,改为下方高度,有问题可以调这里

frameLayoutParams.height = usableHeightSansKeyboard - heightDifference + (bottomSoftKeysHeight / 2);

} else {

// keyboard probably just became hidden

// frameLayoutParams.height = usableHeightSansKeyboard;//之前的,因顶起太高,改为下方高度,有问题可以调这里

frameLayoutParams.height = usableHeightSansKeyboard - (bottomSoftKeysHeight / 2);

}

mChildOfContent.requestLayout();

usableHeightPrevious = usableHeightNow;

}

}

private int computeUsableHeight() {

Rect r = new Rect();

mChildOfContent.getWindowVisibleDisplayFrame(r);

return (r.bottom - r.top);// 全屏模式下: return r.bottom

}

public static boolean isHaveSoftKey(Activity activity) {

Display d = activity.getWindowManager().getDefaultDisplay();

DisplayMetrics realDisplayMetrics = new DisplayMetrics();

d.getRealMetrics(realDisplayMetrics);

int realHeight = realDisplayMetrics.heightPixels;

int realWidth = realDisplayMetrics.widthPixels;

DisplayMetrics displayMetrics = new DisplayMetrics();

d.getMetrics(displayMetrics);

int displayHeight = displayMetrics.heightPixels;

int displayWidth = displayMetrics.widthPixels;

return (realWidth - displayWidth) > 0 || (realHeight - displayHeight) > 0;

}

public static int getBottomSoftKeysHeight(Activity activity) {

Display d = activity.getWindowManager().getDefaultDisplay();

DisplayMetrics realDisplayMetrics = new DisplayMetrics();

d.getRealMetrics(realDisplayMetrics);

int realHeight = realDisplayMetrics.heightPixels;

DisplayMetrics displayMetrics = new DisplayMetrics();

d.getMetrics(displayMetrics);

int displayHeight = displayMetrics.heightPixels;

return (realHeight - displayHeight);

}

}

在对应ActivityFragment组件的 onCreate() 周期内加入 AndroidBug5497Workaround.assistActivity(this)

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_layout)

AndroidBug5497Workaround.assistActivity(this)

}



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。