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是538 ppi约等于ddpi
dpi 像素密度,跟ppi不同的是,dpi可能被人为调整,例如几部相同分辨率不同尺寸的手机ppi是430,440,450,android会dpi指定为480 dpi 约等于ppi
dp density-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);

更多相关文章

  1. Android(安卓)1.6 支持更多的屏幕大小和分辨率
  2. 移动APP测试-Android屏幕适配问题(一)
  3. android 坐标相关
  4. Android手机适配,手机尺寸、px、dpi、dp、sp详解
  5. 移动APP手机兼容性测试初步
  6. 屏幕适配那些事(02)Android逻辑像素刨根问底
  7. Android事件系统(1)
  8. android 组件动画(一)——球的进入效果
  9. Android(安卓)中使用OpenGL ES进行2D开发(绘制第一个三角形番外篇

随机推荐

  1. Android利用Jpush实现异地登陆下线
  2. Android 类加载机制以及基于类加载机制的
  3. 利用AS(3.0)工具将工程打包成jar
  4. WiFi流程
  5. Android 属性动画(Property Animation) 完
  6. 动画 -- View动画 -- 缩放动画
  7. android 学习笔记3--静默安装功能的实现
  8. Android 集成百度地图实现设备定位
  9. Android系统源码阅读(18):Android 应用的显
  10. Android(安卓)系统架构