Android屏幕适配
先来解释一些相关的名词:
屏幕尺寸:也就是我们所说的某某手机是几寸屏,比如HTC one V这款手机是3.7寸的,这里寸所说的是英寸(inch),国际上习惯使用的单位
l inch = 2.54cm, 3.7寸指的就是屏幕的对角线的长度
屏幕分辨率:指的是屏幕的宽和高的像素点数,比如HTC one V是480*800
屏幕密度:每英寸的像素数,比如HTC one V,是252px/inch
px:像素。一块显示屏是由很多的光点组成的,每一个光点就是一个像素。由于这些光点很小很密,想想看,在上面提到的3.7寸的手机上,横向有480个光点,纵向有800个光点,所以显示出来的文字或者图片才会细腻平滑
ppi: 和屏幕密度一个意思
dpi: 每英寸的点数。在电子显示的范畴内它和PPI是一个意思。只有在打印时这个缩写才有意义。在打印领域不存在PPI的叫法,只说DPI,它表示打印机每英寸打印几个像素点。宽和高在同样的像素下,dpi越大,打印出来的图案越小。
dip: 或者叫dp,这是Android开发的一种度量,称作屏幕无关像素。它不表示任何具体的长度或者像素点,这个值只有在具体屏幕密度的手机上,才会被转换为具体的像素值。这个时候才会有实际意义。具体怎么转换,下面进行讲解
下面贴出传说中的HTC one V的截图,带了相关尺寸的标注:(一个很旧的手机,但是在480*800分辨率届很有代表性)
对于一个新发布的手机,厂商一般会指明3个基本的参数:屏幕尺寸、分辨率和ppi。 根据这三个值我们就能算出这个显示屏的长和宽各式多少。
比如:
屏幕宽 = 480/252 ≈ 1.9 inch
屏幕高 = 800/252 ≈ 3.17 inch
注:
对于显示器来说, 横向和纵向的密度是一样的, 也就是说,在屏幕上任意截取一个正方形,它的横向像素数=纵向像素数。
另外我们关心的一点是,这个手机的屏幕密度,对应的drawble目录是哪一个。 这个我们很容易知道 ,是hdpi目录。(怎么就很容易知道了!? 别急别急, 下面就会说到)
这样, 一个手机和显示相关的参数我们就了然于胸了。
#####好了,我们进入正题。;-)
Android项目的res目录下一般加上我们自己创建的,会有6个目录,分别是:drawble drawble-ldpi drawble-mdpi drawble-hdpi drawble-xhdpi drawble-xxhdpi, 这里就不包括更为特殊的drawble目录了,(比如drawlbe-land-hdpi, 表示水平方向的高分辨率的图片,这些都目录不管多么长,它们都是按一丁点规律匹配的, 我们的目的是, 从个别中发现规律,从而应用到整体)
当一个apk运行起来时,Android系统会根据其所运行的手机的屏幕密度去相对应的图片文件夹里找指定名称的图片。 注意, 先去哪个目录里找,完全是根据这个手机的屏幕密度决定的。
其中:注意两点
1、中等分辨率,即mdpi的屏幕密度是160,它是标准的参考密度。所以计算比例的时候它的比值是1,其他屏幕密度的参考比例都是以这个为依据的
2、默认的drawable文件,这个文件存放图片时与mdpi文件是一样的效果。不过一般性的放自定义的selector或者.9的图片
现在我们来看, HTC one V手机的屏幕密度是252ppi, 那距离哪一个最靠近呢, 就是hdpi了。 所以当apk运行在这个手机上时,首先会去这个目录找图片。
Android图片的选择策略
上面说到,如果屏幕对应的文件没有要找的图片的时候,怎么办。这是很常见的一个问题。我们开发项目的时候,我们不会为每一个级别的屏幕去切一套图片。那样做的话,只会让apk很大。所以一般性的图片我们只切一两个典型密度屏幕的图片。但是apk是有可能会从ldpi到xxdpi的各种级别的手机上,这个时候就要根据策略去寻找图片
####Android系统寻找图片的步骤是这样的:
1、去屏幕密度对应的目录去找,如果找到就拿来用
2、如果没有找到,就去比这个密度高一级的目录里面去找,如果找到就拿来用
3、如果没找到,就继续往上找,以此类推
4、如果到了xxhdpi目录的时候还没有找到,就会比自身屏幕密度低一级的目录去找,如果低一级的目录>=hdpi,找到了就拿来用
5、如果没找到, 就去mdpi目录去找, 如果找到了,就拿来用。
6、如果没找到,就去默认的drawble目录里去找, 如果找到了就拿来用。
7、如果没找到,再去最低的ldpi目录里去找。如果找到了,就拿来用。
8、如果没找到, 那就是没找到了, 图片无法显示。(不过一般不会出现这种现象,因为如果每个目录都没有这个图片的话,你是编译不过的)
这里有两点需要注意
1、首先会去比自己密度高的目录里面去找,这是因为系统相信。密度比较高的的目录里面会放置分辨率比较大的图片,这样的话,图片会被缩小,但是同时显示的效果也不会失真。但是如果去低一级的目录去找的话,找到的图片就会被放大,这样的话,图片就会被拉扯的很模糊
e.g. 同一张图片,你在mdpi和xxhdpi目录各放了一份, 这个应用你现在运行在hdpi的手机上, 那应用会选择哪张图片呢。答案是xxhdpi目录里的。即便hdpi离mdpi更近一点!
2、如果在mdpi里找不到是不会直接去ldpi里找的, 而是先去默认的drawble目录里找,这是drawble目录和drawble-mdpi是一个级别的
下面用一张图来表示流程
Android系统对图片的缩放规则
上文中提到如果在手机对应的目录没有找到图片,就会按照一定的策略去其他目录找,那找到了以后就原图显示么? 非也。
对于放在不同目录下的图片, 系统会按照一定比例对原始的图片进行放大或者缩小, 具体的放大缩小比例可参考下表, 图片所在目录和对应的屏幕密度是相同时图片缩放比例为1,也就是原图显示,而横向的比例表示分别放在该密度手机上运行时图片被缩放的比例。
对原始图片的缩放倍数。
上表几点值得注意的地方:
①, drawable目录和drawable-mdpi目录和dp到px的转换关系是一样的。
②,当你放一个120px180px的图片到drawable-hdpi目录,如果此应用运行在一个xhdpi的手机上,则这个图片会被拉扯到160px240px。
③, 最后一行dp->px, 说明了在代码或者布局文件中声明一个dp值, 这个值在不同屏幕密度的手机中会被乘以不同的倍数。 比如你在布局文件中写了一个宽和高分别为120dp和180dp的LinearLayout, 那么当这个应用运行在xhdpi的手机上时(比如上面那个常见手机表中的中兴U985手机),它的实际像素就会被转换为240px360px。 如果运行在ldpi的手机上,就变成了90px135px。 但是在这两个手机中显示的区域大小从肉眼看,是一模一样大的。(这点作为后面内容的一个引子,“看起来”一样大,这就是Android的一个神奇的地方)