目前大家手里握的都是全面屏的手机,而且每家厂商都对全面屏的手机做了手势的支持 确实是从体验上得到了很大的提升,再也不是当年16:9的屏 底部再配个三大金刚的导航按钮 使得有限的可是预览面积更小了。但是2020年依然会有人不使用全面屏手势 选择三大金刚的导航按钮,这就引出了今天的问题。
症状:开启底部虚拟导航按钮,进入全屏显示的页面,此页面有输入框, 这时发现底部被遮挡的问题
看到全屏显示、界面上还有输入框,大家肯定会想到键盘弹出遮挡的bug,还有这个AndroidBug5497Workaround类(如有没使用过的小伙伴 代码贴到下面)
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.
public static void assistActivity (Activity activity) {
new AndroidBug5497Workaround(activity);
}
private View mChildOfContent;
private int usableHeightPrevious;
private FrameLayout.LayoutParams frameLayoutParams;
private AndroidBug5497Workaround(final 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(activity);
}
});
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
}
private void possiblyResizeChildOfContent(Activity activity) {
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);// 全屏模式下: return r.bottom
}
}
我们今天讲的这个问题,其实也是要从这个类来修改
问题就是我们没有去掉底部导航按钮的高度
这个导航栏的高度怎么计算呢?
大部分人会想到拿屏幕的实际高度减去当前可用的高度不就是底部按钮的高度吗,我一开始也是这么想的,没啥大毛病,然后就是一顿撸
/**
* 获取屏幕高度
* @param context
* @return
*/
public static int getScreeHeight(Context context) {
return context.getResources().getDisplayMetrics().heightPixels;
}
/**
* 获取屏幕宽度
* @param context
* @return
*/
public static int getScreeWidth(Context context) {
return context.getResources().getDisplayMetrics().widthPixels;
}
/**
* 获取实际高度
* @param context
* @return
*/
public static int getScreeRealHeight(Context context) {
Display display = getDisplay(context);
if (display == null) {
return 0;
}
DisplayMetrics dm = new DisplayMetrics();
display.getRealMetrics(dm);
return dm.heightPixels;
}
/**
* 获取实际宽度
* @param context
* @return
*/
public static int getScreeRealWidth(Context context) {
Display display = getDisplay(context);
if (display == null) {
return 0;
}
DisplayMetrics dm = new DisplayMetrics();
display.getRealMetrics(dm);
return dm.widthPixels;
}
private static Display getDisplay(Context context) {
WindowManager wm;
if (context instanceof Activity) {
Activity activity = (Activity) context;
wm = activity.getWindowManager();
} else {
wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
}
if (wm != null) {
return wm.getDefaultDisplay();
}
return null;
}
三星手机测试ok 正想结束战斗时。拿一加手机一测试 bug又回来了
所以这种方式获取底部按钮高度是存在兼容性的
最终给出小伙伴们具有兼容性的底部按钮高度的获取:分两种情况 全面屏和非全面屏的获取
1. 全面屏下
* 1.1 开启全面屏开关->返回0
* 1.2 关闭全面屏开关-> 执行非全面屏下处理方式
2. 非全面屏下
* 2.1 没有虚拟键->返回0
* 2.1 虚拟键隐藏->返回0
* 2.2 虚拟键存在且未隐藏-返回虚拟键实际高度
public static int getNavigationBarHeightIfRoom(Context context) {
if(navigationGestureEnabled(context)){
return 0;
}
return getCurrentNavigationBarHeight(((Activity) context));
}
/**
* 全面屏(是否开启全面屏开关 0 关闭 1 开启)
*
* @param context
* @return
*/
public static boolean navigationGestureEnabled(Context context) {
int val = Settings.Global.getInt(context.getContentResolver(), getDeviceInfo(), 0);
return val != 0;
}
/**
* 获取设备信息(目前支持几大主流的全面屏手机,亲测华为、小米、oppo、魅族、vivo都可以)
*
* @return
*/
public static String getDeviceInfo() {
String brand = Build.BRAND;
if(TextUtils.isEmpty(brand)) return "navigationbar_is_min";
if (brand.equalsIgnoreCase("HUAWEI")) {
return "navigationbar_is_min";
} else if (brand.equalsIgnoreCase("XIAOMI")) {
return "force_fsg_nav_bar";
} else if (brand.equalsIgnoreCase("VIVO")) {
return "navigation_gesture_on";
} else if (brand.equalsIgnoreCase("OPPO")) {
return "navigation_gesture_on";
} else {
return "navigationbar_is_min";
}
}
/**
* 非全面屏下 虚拟键实际高度(隐藏后高度为0)
* @param activity
* @return
*/
public static int getCurrentNavigationBarHeight(Activity activity){
if(isNavigationBarShown(activity)){
return getNavigationBarHeight(activity);
} else{
return 0;
}
}
/**
* 非全面屏下 虚拟按键是否打开
* @param activity
* @return
*/
public static boolean isNavigationBarShown(Activity activity){
//虚拟键的view,为空或者不可见时是隐藏状态
View view = activity.findViewById(android.R.id.navigationBarBackground);
if(view == null){
return false;
}
int visible = view.getVisibility();
if(visible == View.GONE || visible == View.INVISIBLE){
return false ;
}else{
return true;
}
}
/**
* 非全面屏下 虚拟键高度(无论是否隐藏)
* @param context
* @return
*/
public static int getNavigationBarHeight(Context context){
int result = 0;
int resourceId = context.getResources().getIdentifier("navigation_bar_height","dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
到此一连串的问题就解决了!!!