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

举报
韩曙亮 发表于 2022/08/20 01:01:25 2022/08/20
【摘要】 文章目录 一、获取设备状态栏高度二、获取设备屏幕数据 参考文档 : 设备兼容性概览屏幕兼容性概览支持不同的像素密度声明受限屏幕支持 上一篇博客 【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

文章来源: hanshuliang.blog.csdn.net,作者:韩曙亮,版权归原作者所有,如需转载,请联系作者。

原文链接:hanshuliang.blog.csdn.net/article/details/126416073

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。