android定义了四种screen-size:

small

normal

large

xlarge

同时定义了六种dpi级别:

ldpi (low) ~120dpi
mdpi (medium) ~160dpi
hdpi (high) ~240dpi
xhdpi (extra-high) ~320dpi
xxhdpi (extra-extra-high) ~480dpi
xxxhdpi (extra-extra-extra-high) ~640dpi

定义这些级别的目的在于更好地组织资源,以适应不同的设备。参见:http://developer.android.com/guide/practices/screens_support.html#range

系统在运行我们的app时,会自动根据当前设备的级别,来加载合适的资源,而我们就需要为不同级别准备各自的资源,如为大屏幕上提供一个并列放置两个view的layout,而小屏幕上则一次只显示一个view。

要做到这一点,我们必须要知道,给定一个设备,如何判断它是哪个级别的?然后才能有的放矢,把相应的资源放在正确的级别目录中。

首先看screen size,这个级别会影响layout模板的选取,即指定一个R.layout.id_XXX时,到底是从res/layout下加载,还是从res/layout-large下加载呢?

先看官方给的图:

第一排是关于size的分档,在这里,各个档是有重叠的,也就是一个大概的范围。

但是我们知道,程序运行时的加载逻辑必须是精确的,针对每一个设备必须获得一个确定的值,以判定它是哪个级别,然后才知道要加载哪些资源。

以上图论,如果我们有一个3.3"的手机,那它到底是small还是normal呢?就无法判断了。

所以,必然要有更准确的计算方法,而这个方法就牵扯到dpi了。

dpi:dot per inch,就是指每英寸上有多少个像素点,要计算这个值,就要知道它的物理尺寸和物理分辨率(也就是全屏有多少实际像素点,或者就是说能发光的元件)

比如我们建一个虚拟设备来看:

它的物理分辨率是720x1280,物理尺寸是4.7"

可能有人疑问,物理尺寸不也是有宽和高吗,怎么才一个值?这个4.7",是对角线的长度。用对角线来做标称,好处是容许更自由的宽高组合吧。

那么要计算这个dpi,按常理就没法算了,因为1个对角线值无法确定惟一的宽高。

但是换一个思路,将面积密度换成线密度,即用对角线上的像素数量来除以对角线长度,其值应该是一致的,所以dpi计算如下:

dpi = sqrt(pixel_width^2+pixel_height^2)/diagonal = sqrt(720^2+1280^2)/4.7 = 312.5

对照上表,可知其dpi级别为xhdpi,与工具界面上显示的一致。

知道了dpi,那么图片类资源的加载目录就知道了,此例中就是res/drawable-xhdpi,但是layout类资源又如何呢?

layout的选取标准与图片资源不同,并不以dpi级别为准,而是要看screen size的级别。

上面在讲screen size分类方法时转而插入对dpi解释,正是为了这里能说清其含义。

实际上官方对screen size的分类标准如下:

  • xlarge screens are at least 960dp x 720dp
  • large screens are at least 640dp x 480dp
  • normal screens are at least 470dp x 320dp
  • small screens are at least 426dp x 320dp

这里给出的宽、高值其实并无单独比较意义,最终结果是看它的乘积。

也就是说最小的屏幕要有426*320=136,320个dp,而要想成为一个中等屏幕则至少需要470*320=150,400个dp,列表如下:

smal = 136,320

normal = 150,400

large = 307,200

xlarge = 691,200

现在问题来了,dp又是什么,和dpi什么关系?针对上例这个设备,它又有多少个dp呢?

先回想一下dpi,它本身是一个比率值,说的是每英寸上有多少个像素点,这是刻划设备能力的一种属性。

然而很多时候能力的绝对值对一般人认知理解来说并不直观(虽然这个例子并不合适,dpi还是很直观的),其相对值才更具有意义。

那么选取第一台android设备为基准,它的dpi是160,其它设备的dpi与160相比,得到一个比率值scale,就是该设备的(dp-)scale,

那么设备的dp则定义为:

dpx = pixel_width/scale

dpy = pixel_height/scale

此例中则其 scale=312.5/160=1.95,dpx=720/scale=369.2,dpy=1280/scale=646.4

也就是以dp单位来衡量,此虚拟设备有一个369 x 646的屏幕,现在可以来计算它的screen size级别了:dp = dpx * dpy = 369 * 646 = 238,374

查上表可知介于150,400和307,200之间,所以它的screen size为normal,当加载layout时,优先使用res/layout里的资源(而非small/large/xlarge)。

定义和计算过程清楚后,再回头审视一下dp的含义,为什么要通过如此曲折的方式来定义这样一个单位。

1、其实从物理分辨率到dp(也就是screen size),只是转换了一下手段,但目的还是一样:就是要解决“数清楚屏幕上到底有多少个点,然后我们的ui面板要做多少个点”这个问题。

2、为什么不直接用“物理像素”,会有什么问题?因为不同设备物理尺寸与分辨率之比差别很大,比较极端的情形是,两个分辨率相同的设备,尺寸却差一半,比如这两:

如果以物理像素定义一个面板为400*600px大小,也就是全屏一半的样子,在10"的tablet上看起来大小正合适,而在4.7"的手机上,那就是小小的一砣,这一砣的物理占地只有tablet上1/16!

如果tablet上的视觉效果是合理的,那么很难想象肉眼如何适应这1/16的同质元素

但是改用dp为单位来描述,结果会是如何呢?(计算结果可以在这个网页方便获取:https://www.sven.de/dpi/)

对前者,dpi=149.5,scale~=1.0,screen size(dp)=800*1280

对后者,dpi=317.6,scale~=2.0,screen size(dp)=384*640

如果我们需要一个在tablet占地1/4(也就是宽高各1/2)的区域,那么其dp大小应为400*640

现在计算其在phone上的占地,先换算为像素大小,w=400*2.0=800,h=640*2.0=1280

即这是一个800*1280像素的区域,几乎刚好是整个Phone屏幕大小(考虑上面计算scale时的舍入误差)

而这个大小,在物理尺寸上刚好和tablet上的1/4是一样的。

可见,使用dp来描述大小的优势在于:确保了该区域在不同分辨率和物理尺寸的屏幕上,其物理面积是一样大的!

而物理面积,正是肉眼观察舒适度的重要衡量标准——而不仅仅是分辨率,相信大家都有体会,很多高清屏手机虽然足够细腻,但如果用来看电子书其实很废眼,远不如较低分辨率但更大尺寸的平板)

现在,dp的含义和好处清楚后,还有最后一个问题:如果真要设计一个面板,到底该给它多少dp呢?dp既是一个虚拟单位,如何直观地以它来估算大小呢?

其实,可以就用dp的来源——第一个android设备的大小作为基准来考虑,它是一个大小为3.2",分辨率为320*480的手机:

在它上面,1个dp就是1个像素。所以,要弄多大的界面,就以它为参考咯!

关于android上dpi/screen-size的厘清解释的更多相关文章

  1. 二十一、Android上常见度量单位【xdpi、hdpi、mdpi、ldpi】解读

    术语和概念 屏幕尺寸 屏幕的物理尺寸,以屏幕的对角线长度作为依据(比如 2.8寸, 3.5寸). 简而言之, Android把所有的屏幕尺寸简化为三大类:大,正常,和小. 程序可以针对这三种尺寸的屏幕 ...

  2. Android上常见度量单位【xdpi、hdpi、mdpi、ldpi】解读

    术语和概念  屏幕尺寸  屏幕的物理尺寸,以屏幕的对角线长度作为依据(比如 2.8寸, 3.5寸).  简而言之, Android把所有的屏幕尺寸简化为三大类:大,正常,和小.  程序可以针对这三种尺 ...

  3. Android上dip、dp、px、sp等单位说明(转)

    dip  device independent pixels(设备独立像素). 不同设备不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA.HVGA和QVGA 推荐使用这个,不依赖像素. 在 ...

  4. Android上dip、dp、px、sp等单位说明

    Android上dip.dp.px.sp等单位说明 dip  device independent pixels(设备独立像素). 不同设备不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA ...

  5. 最牛逼android上的图表库MpChart(二) 折线图

    最牛逼android上的图表库MpChart二 折线图 MpChart折线图介绍 MpChart折线图实例 MpChart效果 最牛逼android上的图表库MpChart(二) 折线图 最近工作中, ...

  6. [原] GLES在iOS和Android上的不同

    本来GLES提供了与native platform的接口 EGL, 然而iOS没有使用EGL接口, 而是自己搞了一套,叫做EAGL的类似东西, 虽然说大同小异,但是在做跨平台的时候还是很恶心. elg ...

  7. Android上使用OpenGLES2.0显示YUV数据

    在Android上用OpenGLES来显示YUV图像,之所以这样做,是因为: 1.Android本身也不能直接显示YUV图像,YUV转成RGB还是必要的: 2.YUV手动转RGB会占用大量的CPU资源 ...

  8. 最牛逼android上的图表库MpChart(三) 条形图

    最牛逼android上的图表库MpChart三 条形图 BarChart条形图介绍 BarChart条形图实例 BarChart效果 最牛逼android上的图表库MpChart(三) 条形图 最近工 ...

  9. android上让我放弃使用wstring来操作中英文字符串 转

    android上让我放弃使用wstring来操作中英文字符串 2013-08-07 16:37:24|  分类: cocos2d|举报|字号 订阅     项目需要,需要对中英文字符串进行遍历修改等, ...

随机推荐

  1. ubuntu14.04 python2.7安装MySQLdb

    安装依赖: sudo apt-get install libmysqlclient-dev libmysqld-dev python-dev python-setuptools 安装MySQLdb p ...

  2. 《程序员代码面试指南》第三章 二叉树问题 Tarjan算法与并查集解决二叉树节点间最近公共祖先的批量查询问题

    题目待续.... Tarjan算法与并查集解决二叉树节点间最近公共祖先的批量查询问题 java代码

  3. es6对象内函数的两种写法

    es6对象内函数一般有两种写法: var person1 = { name: "p1", sayThis() { console.log(this); } }; var perso ...

  4. Cache-Control常用类型

    可缓存性 no-cache 强制所有缓存了此响应的缓存用户,在使用已存储的缓存数据前,发送条件请求到原始服务器,若未过期,则使用缓存数据,否则重新获取 no-store 不存储有关客户端请求或服务器响 ...

  5. codeforces 54A

    题意:收到礼物的规则为每个假日必收到一份礼物,每K天里至少收到一份礼物,求出N天中收到的礼物的最小数量. 思路:将N天根据假日所在天数分为一段段,当假日与假日之间间隔天数hol[i]>-hol[ ...

  6. DL三(向量化编程 Vectorized implementation)

    向量化编程实现 Vectorized implementation 一向量化编程 Vectorization 1.1 基本术语 向量化 vectorization 1.2 向量化编程(Vectoriz ...

  7. Windows- 改变cmd控制台默认显示编码

    在中国的电脑会要求兼容gbk编码,所以微软进入中国市场也顺应中国的要求,其中最明显的就是在cmd上默认的显示就是GBK .当开发人员在运行一些有打印中文的程序时,由于编码采用国际兼容版本的utf_8等 ...

  8. Spark- 流量日志分析

    日志生成 package zx.Utils import java.io.{File, FileWriter} import java.util.Calendar import org.apache. ...

  9. Android 布局文件

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=&q ...

  10. python 链接sharepoint 2013 REST api

    import requests,simplejson from requests_ntlm import HttpNtlmAuth p1 = requests.get("http://you ...