Screen的这些基本概念中,最重要的就是dip的理解,而理解dip就是理解android适配不同设备的关键。
实际物理尺寸。就是我们常说的3.5英寸屏幕,4.7英寸屏幕等等,这个长度说的是对角线的长度。在android中屏幕物理尺寸划分为这么几类:small,normal,large,extra large。下面是对尺寸以及密度的一个粗略分类。该图可能会由于实际设备尺寸和屏幕密度的不断增加而更新,最新的请到官网查看。
图1
“屏幕”分辨率,即屏幕上的像素总数。常用的表现形式如:1280x720, 1920x1080等。
屏幕密度,与dpi表达的同一个意思,两种不同的描述方式。官网如是说:
Screen density
The quantity of pixels within a physical area of the screen; usually referred to as dpi (dots per inch). For example, a "low" density screen has fewer pixels within a given physical area, compared to a "normal" or "high" density screen.
public float density The logical density of the display.
public int densityDpi The screen density expressed as dots-per-inch.
但其实我的理解他就是一个缩放系数,具体原因在后面解释。按照屏幕密度所有的手机可被划分为以下几类:ldpi (low,低密度), mdpi (medium,标准密度), hdpi (high,高密度), and xhdpi (extra high,超大密度)。
每英寸像素数。与density描述的都是屏幕的密度。但请注意这个翻译,实际上应该译为每英寸点数。为说明原因,不得不引入另一个概念:PPI(Pixel per inch),每英寸像素数。实际PPI用于电脑显示领域,DPI用于打印或印刷领域,但从很久之前两个概念就已经开始混用:
“点”有时用来表示像素,特别是计算机市场,由于计算机显示器如LCD或CRT是由一个个极小的点来描绘图像的,LCD显示器在标准屏幕分辨率下,对于一个像素可认为是由显示器的一个“点”来显示,因此ppi有时所写为DPI(dots per inch,每英寸点数)——维基百科:像素
到android这里,干脆就用dpi取代ppi代表像素密度。
像素密度=屏幕总像素数/屏幕大小。通常我们知道屏幕的尺寸是诸如3.5英寸,5.0英寸等,这是对角线长度,我们可以先获取对角线上的总像素数,再除以对角线长即可。
拿Mi2s举例说明:4.3英寸,1280x720。对角线上像素值根据勾股定理可得√(1280^2+720^2)≈1468.6,接着1468.6/4.3≈341.5
然而,从代码测试的结果看起来是有偏差的:
Density:2.0
DensityDpi:320
Resolution:1280x720
xDpi:345.0566 // x方向上(宽)每英寸像素数
yDpi:342.23157 // y方向上(高)每英寸像素数
可以看出,xDpi≈yDpi≈341,与我们的计算结果相近。但DensityDpi是320,为什么呢?在Screen Density中已经说过,android将所有屏幕的实际密度归类,处在某个区间内的密度是个定值,参考下表:
密度分类 | DPI值(像素/英寸) | Density值 |
ldpi |
120 | 0.75 |
mdpi | 160 | 1 |
hdpi |
240 | 1.5 |
xhdpi |
320 | 2 |
xxhdpi |
480 | 3 |
表1
根据图1种的分类,Mi2s的真实dpi为341,341>300,所以Mi2s属于xhdpi,再结合表1,得出DensityDpi=320。
从上面的数据也可以看出Density和DensityDpi值不同,但规律是显而易见的。在android中,mdpi是标准值,android将其density定为1,以此为准得出Density与DensityDpi的关系是:dpi=density*160。
我的疑问是,既然dpi可以代表屏幕密度,还要density干什么?想要搞清楚该死的density,必须要结合dp,往下看。
独立像素,虚拟单位,又称设备无关像素。1dp的长度相当于一个160dpi的屏幕上一个物理像素的长度。而160dpi的屏幕则是被android定义为基准的屏幕(mdpi)。在app运行的时候,android会将dp转为实际像素进行布局。转换的公式为:px = dp * (dpi / 160)。
设想app将一张图以像素为单位进行布局,该图为400px的正方形图,当app运行在1920x1080上时看起来比较小,运行在960x640上时显得非常的大,而我们想要看到的效果是app运行在两个手机上时这张图看起来是大小相近的效果。
看下面这张图是以px为单位进行布局的效果:
图2
下面这张图是使用dp布局的效果:
图3
想要达到这样的效果,就需要在高密度手机上对其进行放大操作,低密度手机上对其进行缩小操作。但是我们无法预期自己的app会安装在什么密度,什么尺寸的手机上,即使知道也不可能为每个手机准备一套图,因此希望android能智能一些,我设置一个大概的尺寸,android能自动适配不同手机。于是就有了独立像素这个单位。见名之意,开发人员只需要用dp或者直接使用wrap_content,剩下的交给android,系统会为你的布局和图片做缩放。
那么,android是如何创造出这个独立像素的?
首先,我们的思路是从原来用px进行布局,改为用dp布局,由于最终dp还是要转化为px,引入一个系数λ,则有:px=dp*λ,λ就是我们的缩放系数;
其次,我最终目标是让所有手机上看到的图大小相同,那么到底多大,是不是要有个标准,我就选一个定做标准,让其他不同密度的手机显示的跟这个标准一样大。那么我把这个标准就定为160像素/英寸吧,取个名字叫mdpi,接着把其他密度的手机进行分类:ldpi(120像素/英寸),hdpi(240像素/英寸),xhdpi(320像素/英寸);
再次,归类都归好了,下面就开始缩放吧:
当app运行在标准手机上(mdpi),图片应该不缩放,因为它是标准,即λ=1,此时px=dp;
当app运行在ldpi手机上时,由于密度小于标准,图像的长更长,宽更宽,为了保持与标准相同的长宽,在ldpi上长要缩小原来的120/160=0.75,宽亦如此,即λ=0.75,此时px=0.75*dp;
当app运行在hdpi上时,λ=1.5,px=1.5*dp;
以此类推。。。
由上面的推导,其实λ=dpi/160=density,可见density就是λ。
1. 从官网的概念得知density与dpi都是描述屏幕密度的,似乎是相同的概念,但何必用两个同名概念来描述让人混淆呢?我个人觉得何不把他们从命名上做个区分,density就是个缩放系数,dpi才是对密度的准确描述。因此我只用dpi来表示屏幕密度,或像素密度,而density其实就是缩放系数,或密度系数;
2. 即使在某一个密度分组区间内(比如xhdpi)不同的密度的手机所展示的同样大小的图片,仔细看也不会完全相同,毕竟他们的密度不同。因此android只是尽最大可能简化适配的工作,分组并不能百分百解决适配的问题。
专用于android中的字体大小。sp产生的初衷与dp是相同的,只是它应用于字体大小。