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

2020-04-03  本文已影响0人  刘小厨

承接Android 屏幕适配

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

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

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

名词解释:

在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;
    }
}
上一篇下一篇

猜你喜欢

热点阅读