文章目录
- 一、获取设备状态栏高度
- 二、获取设备屏幕数据
参考文档 :
- 设备兼容性概览
- 屏幕兼容性概览
- 支持不同的像素密度
- 声明受限屏幕支持
上一篇博客 【Android 屏幕适配】屏幕适配通用解决方案 ② ( 自定义组件解决方案 | 需要解决的问题 : 设计稿坐标数据转为屏幕真实坐标数据 | 实现步骤 ) 中 , 提出 如果要实现将 宽高为 720 x 1232 的设计稿 , 对应 手机屏幕中除 状态栏之外的 布局 , 需要完成如下操作 :
首先 , 要 获取到实际的设备屏幕数据 , 如 手机屏幕实际宽高 , 屏幕像素密度 DPI 等数据 ;
然后 , 计算实际设备的宽高 , 扣掉状态栏的高度 , 不同手机设备状态栏高度不同 , 然后再进行后续计算 ;
再后 , 给出一个 设计稿 与 屏幕实际有效像素值 的 换算比例 ;
最后 , 根据给出的比例 , 在 自定义组件的 onMeasure 方法 中 , 进 行动态换算 , 计算出在当前设备中每个组件的 实际坐标数据 ;
本篇博客中完成前两项工作 ;
一、获取设备状态栏高度
在 com.android.internal.R$dimen.class 字节码类中 , 封装了 设备屏幕尺寸相关属性 , 在这里我们需要获取该字节码类中的 system_bar_height 属性值 ;
首先 , 通过反射获取 com.android.internal.R$dimen 字节码对象 ;
代码语言:javascript复制 // 反射 com.android.internal.R$dimen 类
Class<?> clazz = Class.forName("com.android.internal.R$dimen");
然后 , 调用 Class # newInstance 方法 , 创建 com.android.internal.R$dimen 实例对象 ;
代码语言:javascript复制 // 创建 com.android.internal.R$dimen 实例对象
Object instance = clazz.newInstance();
再后 , 获取上述实例对象的 system_bar_height 字段的值 , 该字段的值是一个 int 类型的 资源 ID ;
代码语言:javascript复制 // 获取指定的字段, 这里用于获取 system_bar_height, 也就是系统状态栏高度
Field field = clazz.getField(systemid);
// 获取字段的值
int fieldValue = (int) field.get(instance);
最后 , 调用 Context # getResources().getDimensionPixelOffset 方法 , 将 dimen 类型的资源 ID 转为实际的像素值 ;
代码语言:javascript复制 // 获取的字段值是资源 ID, 需要转为实际的像素值
return context.getResources().getDimensionPixelOffset(fieldValue);
完整代码 :
代码语言:javascript复制 /**
* 通过反射 com.android.internal.R$dimen 类, 获取其中的某些字段
* @param context 上下文对象
* @param defValue 如果没有成功获取指定字段, 这里返回一个默认值
* @return
*/
public int getDimenValue(Context context, int defValue) {
try {
// 反射 com.android.internal.R$dimen 类
Class<?> clazz = Class.forName("com.android.internal.R$dimen");
// 创建 com.android.internal.R$dimen 实例对象
Object instance = clazz.newInstance();
// 获取指定的字段, 这里用于获取 system_bar_height, 也就是系统状态栏高度
Field field = clazz.getField("system_bar_height");
// 获取字段的值
int fieldValue = (int) field.get(instance);
// 获取的字段值是资源 ID, 需要转为实际的像素值
return context.getResources().getDimensionPixelOffset(fieldValue);
} catch (Exception e) {
// 如果执行出现异常, 则返回默认值
return defValue;
}
}
二、获取设备屏幕数据
获取设备屏幕数据 :
首先 , 获取 WindowManager 实例对象 , 通过调用 Context # getSystemService(Context.WINDOW_SERVICE) 方法 获取 Android 系统服务进行获取该实例 ;
代码语言:javascript复制 // 获取当前设备的屏幕信息
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
然后 , 通过 WindowManager 实例获取 DisplayMetrics 示例对象 , 其中封装了设备真实的屏幕数据参数 ; 通过 DisplayMetrics # heightPixels 可以获取屏幕高度 , 通过 DisplayMetrics # widthPixels 可以获取屏幕宽度 ;
代码语言:javascript复制 DisplayMetrics displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
再后 , 获取手机状态栏高度 ;
代码语言:javascript复制 // 获取状态框高度
int statusBarHeight = getDimenValue(context,48);
最后 , 处理状态栏信息 , 如果是横屏 , 在宽度方向上减去状态栏高度 , 如果是竖屏 , 在高度上减去状态栏高度 ; 这里通过对比屏幕的宽高来判定当前是横屏还是竖屏 ;
代码语言:javascript复制 // 在屏幕真实宽高上减去状态栏高度
if(displayMetrics.widthPixels > displayMetrics.heightPixels){
// 宽度大于高度说明是横屏状态, 状态栏在左侧或者右侧
this.screenWidth = displayMetrics.heightPixels;
this.screenHeight = displayMetrics.widthPixels - statusBarHeight;
}else{
// 高度大于宽度说明是竖屏状态, 状态栏在上侧
this.screenWidth = displayMetrics.widthPixels;
this.screenHeight = displayMetrics.heightPixels - statusBarHeight;
}
完整代码如下 :
代码语言:javascript复制 private void initMetrics(){
// 获取当前设备的屏幕信息
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
if(screenWidth == 0.0f || screenHeight == 0.0f){
//获取状态框信息
int statusBarHeight = getDimenValue(context,48);
// 在屏幕真实宽高上减去状态栏高度
if(displayMetrics.widthPixels > displayMetrics.heightPixels){
// 宽度大于高度说明是横屏状态, 状态栏在左侧或者右侧
this.screenWidth = displayMetrics.heightPixels;
this.screenHeight = displayMetrics.widthPixels - statusBarHeight;
}else{
// 高度大于宽度说明是竖屏状态, 状态栏在上侧
this.screenWidth = displayMetrics.widthPixels;
this.screenHeight = displayMetrics.heightPixels - statusBarHeight;
}
}
}