• 【Android 屏幕适配】屏幕适配通用解决方案 ③ ( 自定义组件解决方案 | 获取设备状态栏高度 | 获取设备屏幕数据 )



    参考文档 :


    上一篇博客 【Android 屏幕适配】屏幕适配通用解决方案 ② ( 自定义组件解决方案 | 需要解决的问题 : 设计稿坐标数据转为屏幕真实坐标数据 | 实现步骤 ) 中 , 提出 如果要实现将 宽高为 720 x 1232 的设计稿 , 对应 手机屏幕中除 状态栏之外的 布局 , 需要完成如下操作 :


    首先 ,获取到实际的设备屏幕数据 , 如 手机屏幕实际宽高 , 屏幕像素密度 DPI 等数据 ;

    然后 , 计算实际设备的宽高 , 扣掉状态栏的高度 , 不同手机设备状态栏高度不同 , 然后再进行后续计算 ;

    再后 , 给出一个 设计稿屏幕实际有效像素值换算比例 ;

    最后 , 根据给出的比例 , 在 自定义组件的 onMeasure 方法 中 , 进 行动态换算 , 计算出在当前设备中每个组件的 实际坐标数据 ;


    本篇博客中完成前两项工作 ;





    一、获取设备状态栏高度



    com.android.internal.R$dimen.class 字节码类中 , 封装了 设备屏幕尺寸相关属性 , 在这里我们需要获取该字节码类中的 system_bar_height 属性值 ;


    首先 , 通过反射获取 com.android.internal.R$dimen 字节码对象 ;

                // 反射 com.android.internal.R$dimen 类
                Class<?> clazz = Class.forName("com.android.internal.R$dimen");
    
    • 1
    • 2

    然后 , 调用 Class # newInstance 方法 , 创建 com.android.internal.R$dimen 实例对象 ;

                // 创建 com.android.internal.R$dimen 实例对象
                Object instance = clazz.newInstance();
    
    • 1
    • 2

    再后 , 获取上述实例对象的 system_bar_height 字段的值 , 该字段的值是一个 int 类型的 资源 ID ;

                // 获取指定的字段, 这里用于获取 system_bar_height, 也就是系统状态栏高度
                Field field = clazz.getField(systemid);
                // 获取字段的值
                int fieldValue = (int) field.get(instance);
    
    • 1
    • 2
    • 3
    • 4

    最后 , 调用 Context # getResources().getDimensionPixelOffset 方法 , 将 dimen 类型的资源 ID 转为实际的像素值 ;

                // 获取的字段值是资源 ID, 需要转为实际的像素值
                return context.getResources().getDimensionPixelOffset(fieldValue);
    
    • 1
    • 2

    完整代码 :

        /**
         * 通过反射 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;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23




    二、获取设备屏幕数据



    获取设备屏幕数据 :

    首先 , 获取 WindowManager 实例对象 , 通过调用 Context # getSystemService(Context.WINDOW_SERVICE) 方法 获取 Android 系统服务进行获取该实例 ;

            // 获取当前设备的屏幕信息
            WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            DisplayMetrics displayMetrics = new DisplayMetrics();
            windowManager.getDefaultDisplay().getMetrics(displayMetrics);
    
    • 1
    • 2
    • 3
    • 4

    然后 , 通过 WindowManager 实例获取 DisplayMetrics 示例对象 , 其中封装了设备真实的屏幕数据参数 ; 通过 DisplayMetrics # heightPixels 可以获取屏幕高度 , 通过 DisplayMetrics # widthPixels 可以获取屏幕宽度 ;

            DisplayMetrics displayMetrics = new DisplayMetrics();
            windowManager.getDefaultDisplay().getMetrics(displayMetrics);
    
    • 1
    • 2

    再后 , 获取手机状态栏高度 ;

                // 获取状态框高度
                int statusBarHeight = getDimenValue(context,48);
    
    • 1
    • 2

    最后 , 处理状态栏信息 , 如果是横屏 , 在宽度方向上减去状态栏高度 , 如果是竖屏 , 在高度上减去状态栏高度 ; 这里通过对比屏幕的宽高来判定当前是横屏还是竖屏 ;

                // 在屏幕真实宽高上减去状态栏高度
                if(displayMetrics.widthPixels > displayMetrics.heightPixels){
                    // 宽度大于高度说明是横屏状态, 状态栏在左侧或者右侧
                    this.screenWidth = displayMetrics.heightPixels;
                    this.screenHeight = displayMetrics.widthPixels - statusBarHeight;
                }else{
                    // 高度大于宽度说明是竖屏状态, 状态栏在上侧
                    this.screenWidth = displayMetrics.widthPixels;
                    this.screenHeight = displayMetrics.heightPixels - statusBarHeight;
                }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    完整代码如下 :

        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;
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    retrofit-spring-boot-starter这款轻量级 HTTP 神器好用到爆
    A Recommendation for interface-based programming
    5.盒子阴影(重点)
    《docker基础篇》1.Docker简介,包括Docker是什么、容器与虚拟机比较、能干嘛、去哪下
    Springboot2+thymeleaf+Jpa实现CRUD操作
    Nuclei(二)进阶——深入理解workflows、Matchers和Extractors
    什么是原生IP?原生IP与住宅IP有何区别?
    list容器 常用 API操作
    Linux命令:free命令
    Linux - 札记 - W10: Warning: Changing a readonly file
  • 原文地址:https://blog.csdn.net/han1202012/article/details/126416073