需求场景: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
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。