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

Android开发中的各种单位的解释


  • 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 手机设备为例:

Dpi :

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

Density

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

Dip

  1. 先明白一个概念,所有显示到屏幕上的图像都是以 px 为单位。
  2. Dip 是我们开发中使用的长度单位,最后他也需要转换成 px。
  3. 计算这个设备上 1dip 等于多少 px:
    px = dip x dpi /160
    px = 1 x 445 / 160 = 2.78
  4. 通过上面的计算可以看出在此设备上 1dip = 2.78px,那么这是一个真实的故事吗? nonono,其中的关键值 dpi 并不是我们算出来的 445 ,请往下看。

Android 系统定义的 Dpi


上面计算的 445Dpi 是在 4.95 英寸下的 1920*1080 手机,那如果是 4.75 分辨率下的呢? 4.55 分辨率下的呢?。。。。可见是很麻烦的,同一个分辨率在不同的屏幕尺寸上 Dpi 也不相同。为了解决这个问题, Android 中内置了几个默认的 Dpi ,在特定的分辨率下自动调用,也可以手动在配置文件中修改。

ldpi mdpi hdpi xhdpi xxhdpi
分辨率 240x320 320x480 480x800 720x1280 1080x1920
系统dpi 120 160 240 320 480
基准比例 0.75 1 1.5 2 3

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

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

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

height = 100 x 445 / 160 = 278.5px
width  = 200 x 445 / 160 = 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
内部计算过程为:

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 得到比例,我们这样看:

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

其中的480/160其实就是在求基准比例,这里得到3。如果在熟悉上表的情况下看到机型的分辨率,在设置dp的时候可以直接心算出相对应的px,心算过程如下:

分辨率:1080x1920 -> 系统 DPI:480 -> 基准比例:480 / 160 = 3 -> 对应px:100 x 3 = 300
分辨率:720x1280 -> 系统 DPI:320 -> 基准比例:320 / 160 = 2 -> 对应px:100 x 2 = 200
分辨率:480x800 -> 系统 DPI:240 -> 基准比例:240 / 160 = 1.5 -> 对应px:100 x 1.5 = 150
分辨率:320x480 -> 系统 DPI:160 -> 基准比例:160 / 160 = 1 -> 对应px:100 x 1 = 100
分辨率:240x320 -> 系统 DPI:120 -> 基准比例:120 / 160 = 0.75 -> 对应px:100 x 0.75 = 75
...................

总结:

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;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容