Android开发中dip,dpi,density,px等详解(包含转换过程和讲解)

Android开发中dip,dpi,density,px等详解

首先,解释一下各种单位:

.Px (Pixel像素)
也称为图像元素,是作为图像构成的基本单元,单个像素的大小并不固定,跟随屏幕大小和像素数量的关系变化(屏幕越大,像素越低,单个像素越大,反之亦然)。所以在使用像素作为设计单位时,在不同的设备上可能会有缩放或拉伸的情况。

.Resolution(分辨率)
是指屏幕的垂直和水平方向的像素数量,如果分辨率是 1920*1080 ,那就是垂直方向有 1920 个像素,水平方向有 1080 个像素。

.Dpi(像素密度)
是指屏幕上每英寸(1英寸 = 2.54 厘米)距离中有多少个像素点。如果屏幕为 320*240,屏幕长 2 英寸宽 1.5 英寸,Dpi = 320 / 2 = 240 / 1.5 = 160。

.Density(密度)
这个是指屏幕上每平方英寸(2.54 ^ 2 平方厘米)中含有的像素点数量。

.Dip / dp (设备独立像素)
也可以叫做dp,长度单位,同一个单位在不同的设备上有不同的显示效果,具体效果根据设备的密度有关,详细的公式请看下面

计算规则

以一个 4.95 英寸 1920 * 1080 的 nexus5 手机设备为例:
4.95英寸为左上角到右下角即直角边长度

Dpi :(像素密度)

  1. 计算直角边像素数量: 19202+10802=2202^2(勾股定理)。
  2. 计算 DPI:2202 / 4.95 = 445。
  3. 得到这个设备的 DPI 为 445 (每英寸的距离中有 445 个像素)

Density:(密度)

上面得到每英寸中有 445 像素,那么 density 为每平方英寸中的像素数量,应该为: 445^2=198025。

Dip/dp:(设备独立像素)

  1. 先明白一个概念,所有显示到屏幕上的图像都是以 px 为单位。

  2. Dip 是我们开发中使用的长度单位,最后他也需要转换成 px。

  3. 计算这个设备上 1dip 等于多少 px:
    px = dip x dpi /160
    px = 1 x 445 / 160 = 2.78

    注:android中以分辨率为320x480,即dpi为160为基准值,dpi为160时,1px = 1dp

  4. 通过上面的计算可以看出在此设备上 1dip = 2.78px,那么这是一个真实的故事吗? nonono,其中的关键值 dpi 并不是我们算出来的 445 ,请往下看。

  5. Android 系统定义的 Dpi

    在上面计算中我们得到一个 4.95 英寸 1920 * 1080的手机dpi为445。但是android有很多的分辨率,而且即使是同一个分辨率,在不同尺寸的手机中dpi也不相同,很麻烦,为例解决这个问题,Android 中内置了几个默认的 Dpi ,在特定的分辨率下自动调用,也可以手动在配置文件中修改。

    ldpimdpihdpixhdpixxhdpi
    分辨率240x320320x480480x800720x12801080x1920
    系统dpi120160240320480
    基准比例0.7511.523

这是内置的 Dpi ,啥意思? 在 1920*1080 分辨率的手机上 默认就使用 480 的 dpi ,不管的你的尺寸是多大都是这样,除非厂家手动修改了配置文件,这个我们后面再说。
我们亲自尝试一下:

<TextView    
  android:id="@+id/tv"   
  android:layout_width="200dp"    
  android:layout_height="100dp"    
  android:text="Hello World!" />

这是一个宽200dp,高100dp的textView,按照我们之前的公式手动计算:

height = 100 x 445 / 160 = 278.5px
width  = 200 x 445 / 160 = 556.25px

根据dpi为445计算出的px为高278.5px 宽556.25px

之后用代码验证一下:
layout = (RelativeLayout)findViewById(R.id.la);
//要在控件绘制完成后才能获取到相关信息,所以这里要监听绘制状态

layout.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()     {    
  public boolean onPreDraw() {        
    Log.d("hehehe", textView.getHeight() + "/" + textView.getWidth());       
    return true;    
  }
});

输出的结果为:300/600,可见,在内部高画了300px,宽画了600px

所以重新推导一下计算:

height = 100 x 480 / 160 = 300px
width  = 200 x 480 / 160 = 600px

其中的 160 是基准值不会变的, 100 和200 是我们设置的 dp ,那么这 480 是从何而来的?说好的 445 呢?
找到我们手机中的 /system/build.prop 文件,其中有一行是这样:
ro.sf.lcd_density=480

这就指定了这个机型使用的dpi是多少,还有一种情况是没有这一行(我在模拟器中发现过),那么应该是根据表格中的分辨率来自动设置。

我更改这行为:
ro.sf.lcd_density=320

再次运行上面的测试代码,输出结果为:200/400

再次推导一下计算:

height = 100 x 320 / 160 = 200px
width  = 200 x 320 / 160 = 400px

说到底,因为有dpi这个动态的系数,我们在使用dp的时候才能兼容不同分辨率的设备。

到这里,应该都明白了 dpi 的由来,以及系统 dpi 跟物理 dpi 并不一定相同。在系统中使用的全部都是系统 dpi,没有使用物理 dpi,也获取不到物理 dpi。物理 dpi 主要用于厂家对于手机的参数描述(也可以看做 ppi )!

然后。。表格中还有一个东西叫做基准比例,这个其实就是计算 dp -> px 中重要的系数,以 160 为基准,其他的除以 160 得到比例。

以 160 为基准:dpi的越大1dp转换为px的值也就越大

总结:

1. dpi(每英寸像素数)是有预设值的!120-160-240-320-480。对应不同的分辨率。

2. 基准比例 = dpi(每英寸像素数) / 160

3. px = dp x 基准比例

我们主要使用的类是:DisplayMetrics

以下为官方api说明
A structure describing general information about a display, such as its size, density, and font scaling.
To access the DisplayMetrics members, initialize an object like this:

DisplayMetrics metrics = newDisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);

这是一个获取屏幕信息的类,比如大小,密度等。以及初始化的方法。

实际运用如下:

DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
//通常我们在使用DisplayMetrics时,都是直接获取内部变量来使用。所以下面直接列出各个内部变量。

dm.ydpi;     //得到物理屏幕上 Y 轴方向每英寸的像素
dm.xdpi;     //得到物理屏幕上 X 轴方向每英寸的像素 
             //ps:  其实这两个大多数情况下都是相同的
             //你能想象上面像素密度大很清晰 下面密度小跟马赛克一样吗 233333

dm.density;           //获取当前设备的基准比例
dm.densityDpi;        //获取系统dpi,随着 build.prop 文件中的代码而改变。

dm.widthPixels;       //获取屏幕宽度的像素数量

//获取屏幕高度的像素数量!
//注意 - 因为这里会自动减去32dp的像素数量,根据分辨率不同的设备,减去的像素数量也不同,但是可以根据公式推算完整(px = dp x 基准比例)。
/*为啥不用dm.densityDpi / 160 得到基准比例?
  因为那个会随着build.prop文件代码变更而更改,算出来的不一定准确*/
dm.heightPixels + 32 * dm.ydpi / 160;
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值