全面屏虚拟按键高度适配

需求场景:ScrollView中需要一个定高的recyclerView,其高度为屏幕高度,本以为一个简单的需求,调试了半天.

最初的高度获取
public static int getScreenHeight(Context context) {
final Resources resources = context.getResources();
final DisplayMetrics dm = resources.getDisplayMetrics();
return dm.heightPixels;
}
复制代码测试结果(PS:测试机有限,欢迎更多人加入测试,发现未知的问题)

手机类型
getScreenHeight()
getRealHeight()
状态栏
虚拟按键

Mi8虚拟按键模式
2120
2340
110
130

Mi8手势模式
2120
2340
110
130

华为Mate20虚拟按键模式
2094
2244
81
114

华为Mate20手势模式
2163
2244
81
114

vivo-z20虚拟按键模式
2154
2280
84
126

vivo-z20手势模式
2280
2280
84
126

由测试可以看出,getScreenHeight()获取的高度在各平台是不统一的,原因也各异:

理论上 getScreenHeight()获取的是可用高度,即屏幕整体高度减去占用的状态栏和虚拟按键.
小米不区分是否使用了虚拟按键.
华为,手势模式下正常,但虚拟按键模式高度有偏差.
vivo,获取的高度多了状态栏高度.

而获取真实高度,状态栏高度,虚拟按键高度,可以获取一致的值,因此最终方案采用 真实高度- 状态栏高度- 虚拟按键高度来获取真实的可用高度(PS:由于现今绝大部分项目都不使用ActionBar,所以未考虑ActionBar的影响).
真实的可用高度获取(真实全屏高度- 状态栏高度- 虚拟按键高)

获取真实高度

public static int getRealHeight(Context context) {
    Display display = getDisplay(context);
    if (display == null) {
        return 0;
    }
    DisplayMetrics dm = new DisplayMetrics();
    display.getRealMetrics(dm);
    return dm.heightPixels;
}

复制代码
状态栏高度

public static int getStatusHeight() {
int height = 0;
int resourceId = Latte.getApplicationContext().getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
height = Latte.getApplicationContext().getResources().getDimensionPixelSize(resourceId);
}
return height;
}
复制代码
虚拟按键是否使用

检测是否是全面屏模式,如果是,不需考虑虚拟键
检测虚拟按键是否隐藏了

/**
 * 非全面屏下 虚拟按键是否打开
 *
 * @param activity activity
 * @return 虚拟按键是否打开
 */
private 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;
    }
}

/**
 * 全面屏(是否开启全面屏开关 0 关闭  1 开启)
 *
 * @param context activity
 * @return 是否是前面屏
 */
private static boolean navigationGestureEnabled(Context context) {
    int val = Settings.Global.getInt(context.getContentResolver(), getDeviceInfo(), 0);
    return val != 0;
}

复制代码
虚拟按键高度

private 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;
}

复制代码
可用高度
有了上面这些信息,即可获取真实的可用区域高度: getScreenHeightReal(context) - getStatusHeight() - getNavigationBarHeightIfRoom(context)

工具类路径
相关知识(Display&&DisplayMetrics)

DisplayMetrics: 提供屏幕的通用信息,如显示大小,分辨率和字体
Display:提供逻辑显示区域大小、密度的相关信息

本次用的的方法

context.getResources().getDisplayMetrics(): 包含可视区域的屏幕信息的DisplayMetrics;
activity.getWindowManager().getDefaultDisplay(): 获取当前屏幕信息的 Display;
display.getMetrics(DisplayMetrics outMetrics): 将dispay的可视区信息填入outMetics;
display.getRealMetrics(DisplayMetrics outMetrics) :将dispay的真实区域(即完整屏幕区域)信息填入outMetics;

作者:wangfengye
链接:https://juejin.cn/post/6844903829595504648
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章