美文网首页
Android 屏幕适配-像素密度适配

Android 屏幕适配-像素密度适配

作者: 刘小厨 | 来源:发表于2020-04-03 20:20 被阅读0次

    承接Android 屏幕适配

    说明:本文仅为简单思路,没有实现项目适用的轮子

    通过修改系统像素密度做屏幕适配的主要思路是:

    通过修改density, scaleDensity, densityDpi值直接更改系统内部对于
    目标尺寸而言的像素密度,达到屏幕适配的目的。

    名词解释:

    • density:表示屏幕在一英寸像素点/160 的比值,如果屏幕在一英寸范围呢的像素点有160个,那么density=1,如果屏幕在一英寸范围呢的像素点有320个,那么density=2
      这里xx英寸一般指屏幕对角线的长度

    • scaleDensity: 表示字体缩放比例,默认scaleDensity =density

    • densityDpi: 表示屏幕上每一英寸的像素点有多少个,就是上述的160,320等值

    在Android中,控件呈现到屏幕上的尺寸,最终都会换算成像素为单位,也就是px(无论xml中声明的dp,pt,sp最终都会换算成像素px)

    Android xml声明的尺寸单位是在TypedValue类的applyDimension(int unit, float value, DisplayMetrics metrics)方法中完成转换的,代码如下

    public static float applyDimension(int unit, float value,
                                           DisplayMetrics metrics)
        {
            switch (unit) {
            case COMPLEX_UNIT_PX:
                return value;
            case COMPLEX_UNIT_DIP:
                return value * metrics.density;
            case COMPLEX_UNIT_SP:
                return value * metrics.scaledDensity;
            case COMPLEX_UNIT_PT:
                return value * metrics.xdpi * (1.0f/72);
            case COMPLEX_UNIT_IN:
                return value * metrics.xdpi;
            case COMPLEX_UNIT_MM:
                return value * metrics.xdpi * (1.0f/25.4f);
            }
            return 0;
        }
    

    从上面的代码中也可以看出,修改DisplayMetrics的 density以及scaledDensity可以影响控件最终的像素值
    因为Android 的碎片化现象比较严重,不同的设备density值可能不一样,相同分辨率的设备的density值也有可能不一样,所以调整或优化处理density的值就是一种Android屏幕适配的方案
    我们期望的是density随着屏幕分辨率的变化而变化,也就是相同分辨率的设备,我们希望density的值是相同的

    这种思路实现的屏幕适配比较全面,下面贴下代码,使用的话直接在Activity的setContentView()方法之前调用即可Density.setDensity(getApplication(),this)
    或者在Application中通过registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks())注册Activity的生命周期监听,在回调方法onActivityCreated(Activity activity, Bundle savedInstanceState)中调用Density.setDensity(Application.this, activity)

    public class Density {
        private static final float  WIDTH = 320;//参考设备的宽,单位是dp 320 / 2 = 160
        private static float appDensity;//表示屏幕密度
        private static float appScaleDensity; //字体缩放比例,默认appDensity
    
        public static void setDensity(final Application application, Activity activity){
            //获取当前app的屏幕显示信息
            DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();
            if (appDensity == 0){
                //初始化赋值操作
                appDensity = displayMetrics.density;
                appScaleDensity = displayMetrics.scaledDensity;
                //添加字体变化监听回调
                application.registerComponentCallbacks(new ComponentCallbacks() {
                    @Override
                    public void onConfigurationChanged(Configuration newConfig) {
                        //字体发生更改,重新对scaleDensity进行赋值
                        if (newConfig != null && newConfig.fontScale > 0){
                            appScaleDensity = application.getResources().getDisplayMetrics().scaledDensity;
                        }
                    }
    
                    @Override
                    public void onLowMemory() {
    
                    }
                });
            }
    
            //计算目标值density, scaleDensity, densityDpi
            float targetDensity = displayMetrics.widthPixels / WIDTH; // 1080 / 360 = 3.0
            float targetScaleDensity = targetDensity * (appScaleDensity / appDensity);
            int targetDensityDpi = (int) (targetDensity * 160);
            //替换Activity的density, scaleDensity, densityDpi
            DisplayMetrics dm = activity.getResources().getDisplayMetrics();
            dm.density = targetDensity;
            dm.scaledDensity = targetScaleDensity;
            dm.densityDpi = targetDensityDpi;
        }
    }
    

    相关文章

      网友评论

          本文标题:Android 屏幕适配-像素密度适配

          本文链接:https://www.haomeiwen.com/subject/wrwkphtx.html