Android 终极屏幕适配方案

Android 屏幕适配问题的由来

我们都知道 Android 碎片化问题令人痛心疾首,而造成的屏幕差异正式碎片化的问题中心。
屏幕的尺寸从3英寸到10英寸,分辨率从320到1920应有尽有,这对我们ui适配问题造成很大的困难。对于屏幕碎片化问题,Android 官方推荐使用dp作为尺寸单位来适配ui,因此我们很有必要清楚px,dp,dpi,ppi,density这些概念。

定义概念转化
px像素点,比如手机分辨率320 x 480表示宽有320像素,高有480像素px = density * dp
ppi像素密度,每英寸包含的像素数目,这是屏幕物理参数,例如mate 20 pro 的ppi是538ppi约等于ddpi
dpi像素密度,跟ppi不同的是,dpi可能被人为调整,例如几部相同分辨率不同尺寸的手机ppi是430,440,450,android会dpi指定为480dpi 约等于ppi
dpdensity-independent pixels,基于屏幕物理分辨率一个抽象单位,用来说明与密度无关的尺寸px = dp *(dpi / 160)
density密度,屏幕每平方英寸还有的像素点数量density = dpi/160)

一般来说,通过dp和自适应布局可以基本解决屏幕碎片化问题,这也是Android 推荐使用的屏幕兼容性方案,但是它也会存在两个比较大的问题:

  • 不一致性。因为dpi与ppi的差异实际的差异性,导致在相同分辨率的手机上,控件实际大小会有所不同。
  • 效率。设计师的设计稿都是由px为单位的,开发人员为了适配需要换算成dp。

除了dp适配之外,今天我要讲的是通过修改系统density来适配。

在编写xml文件时候,无论我们给控件的宽高用dp还是px,还是pt,最终android会把它转换成px显示。通过一下源码可以得知。

   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;
    }

所以可以发现当我们用dp时候,系统都会讲我们dp 值 乘以metrics.density换算的px值显示到手机上,sp的话则是乘以metrics.scaledDensity,默认情况下,metrics.scaledDensity = metrics.density。所以我们只要通过修改系统的metrics.density 就能达到适配的效果。
那么怎么修改呢?我们可以让ui出图时候定一个参考的宽度的值,比如width = 320dp;然后我们可以根据当前手机的displayMetrics.widthPixels / width算出density从而替换系统的density。话不多说上代码~

public class Density {

    private static final float  WIDTH = 320;//参考设备的宽

    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;

        //计算目标值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;
    }

}

根据当前手机宽的像素值/参考的宽度值 算出目标density,然后替换掉系统的即可。
然后mainActivity 里调用Density.setDensity(getApplication(),this);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值