在APP使用过程中(尤其是在华为、vivo等国产手机上),会出现以下适配问题:
- 底部导航栏遮挡住footerBar或其他内容
- 状态栏遮挡住header等内容
- 初始化时正常,弹出键盘或从后台再切换回来时再次出现1问题并不可还原
- 彻底隐藏底部导航栏时,部分手机无法唤起底部导航栏,又不支持上滑或左滑来切出,从而导致无法退出APP
解决方案
网上很多博客建议使用fitsystemwindows,如这篇博客,但是因为当前APP是cordova项目,不能轻易更改cordova的webView初始化代码,此方案无效,即使实现也会有漏网之鱼。最终解决方案是在布局变化时(后台切回、键盘弹出收起等)重新计算页面高度,动态更新。从而解决问题。
参考资料: 参考资料
实施步骤
1. 重写StatusBar.java 的run方法,改后如下
public void initialize(final CordovaInterface cordova, CordovaWebView webView) {
LOG.v(TAG, "StatusBar: initialization");
super.initialize(cordova, webView);
this.cordova.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
Window window = cordova.getActivity().getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
//添加内容end
window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
}
});
}
2. 将config.xml中的resizeOnFullScreen设置为false
此举是为了避免keyboard插件又重新计算一次,导致出错
3. 动态计算代码: FixScreen.java
package com.tehang.TMC;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import java.lang.reflect.Method;
public class FixScreen {
public static void assistActivity(View content) {
new FixScreen(content);
}
private View mChildOfContent;
private int usableHeightPrevious;
private ViewGroup.LayoutParams frameLayoutParams;
private FixScreen(View content) {
mChildOfContent = content;
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
possiblyResizeChildOfContent();
}
});
frameLayoutParams = mChildOfContent.getLayoutParams();
}
private void possiblyResizeChildOfContent() {
int usableHeightNow = computeUsableHeight();
Log.d("usableHeightNow", "possiblyResizeChildOfContent() returned: " + usableHeightNow);
if (usableHeightNow != usableHeightPrevious) {
frameLayoutParams.height = usableHeightNow;
mChildOfContent.requestLayout();
usableHeightPrevious = usableHeightNow;
}
}
private int computeUsableHeight() {
Rect r = new Rect();
mChildOfContent.getWindowVisibleDisplayFrame(r);
return (r.bottom);
}
public static boolean checkDeviceHasNavigationBar(Context context) {
boolean hasNavigationBar = false;
Resources rs = context.getResources();
int id = rs.getIdentifier("config_showNavigationBar", "bool", "android");
if (id > 0) {
hasNavigationBar = rs.getBoolean(id);
}
try {
Class systemPropertiesClass = Class.forName("android.os.SystemProperties");
Method m = systemPropertiesClass.getMethod("get", String.class);
String navBarOverride = (String) m.invoke(systemPropertiesClass, "qemu.hw.mainkeys");
if ("1".equals(navBarOverride)) {
hasNavigationBar = false;
} else if ("0".equals(navBarOverride)) {
hasNavigationBar = true;
}
} catch (Exception e) {
}
return hasNavigationBar;
}
}
4. 在MainActivity.java中调用FixScreen,代码如下:
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
if (extras != null && extras.getBoolean("cdvStartInBackground", false)) {
moveTaskToBack(true);
}
loadUrl(launchUrl);
fixScreenOverlap();
removeInviteTokenData();
}
/** 修复导航栏和状态栏引起的遮挡问题 */
private void fixScreenOverlap(){
if (FixScreen.checkDeviceHasNavigationBar(this)) {
FixScreen.assistActivity(findViewById(android.R.id.content));
}
}
网友评论