开篇
近日,在研究屏幕适配的问题,由于涉及比较多概念,例如ppi、dpi、dip、px等等,在适配屏幕的时候经常不得要领,写此文章,做个总结。
相关名词
屏幕尺寸: 也就是我们平时所说的某某手机是几寸屏, 比如HTC one V这款手机是3.7寸的, 这里的寸说的是英寸(inch),国际上习惯使用的单位,1inch = 2.54cm,3.7寸指的是屏幕的对角线的长度。
屏幕分辨率: 指屏幕的宽和高的像素数, 比如HTC one V是480x800的。
屏幕密度: 每英寸的像素数,比如HTC one V, 是252 px/inch。
px: 像素。一块显示屏是由很多的光点组成的,每一个光点就是一个像素。由于这些光点很小很密,想想看,在上面提到的3.7寸的手机上,横向有480个光点,纵向有800个光点,所以显示出来的文字或者图片才很细腻平滑。
ppi: 和屏幕密度一个意思, 全称是pixel per inch. 是专业一点的叫法。
dpi: dot per inch,每英寸的点数。在电子显示范畴内它和PPI是一个意思。 只有在打印时这个缩写才有意义,在打印领域不存在 PPI的叫法,只说DPI,它表示打印机每英寸打印几个像素点。宽高同样像素下,dpi越大,打印出来的图案越小。
dip: 或者叫dp,这是开发中特有的一种度量,称作屏幕无关像素, 它不表示任何具体的长度或者像素点, 这个值只有在 具体屏幕密度的手机上,才会被转换为具体的像素值。 这个时候才会有实际意义。
dip在屏幕中显示
首先看图:
drawable文件夹dpi与屏幕ppi的关系(图1) dip与相应dpi放大系数(图2)首先,假设我们需要设计一个屏幕宽的控件而不使用match_parent在这个参数,在一个1280x720像素,5英寸的屏幕中,我们可以计算出该屏幕的dpi(ppi)=(12802+7202)^0.5 / 5 = 1468.60 / 5 = 293.72 , 根据上表可知:240dpi<293.72dpi<320dpi,所以该屏幕对应的主流像素密度xhdpi,此时由图2我们可知,在该屏幕设计1dip的长度,其实际尺寸应为2px。此时,需要设计一个控件其宽为屏幕宽(720px),我们就可以将其width设置为720 / 2 = 360dip。
看到这里,你或许会有疑问:在不同屏幕尺寸,设计一个占据屏幕宽的控件,难道都需要这么麻烦吗?也不一定是。
我们再举一个常见的屏幕尺寸:1920x1080像素,5.5英寸的屏幕。通过计算得出dpi=400.53,属于xxhdpi。当我们设置360dip时,屏幕的实际像素为540px刚好为屏幕的一半1080px。
那么,是否能得出360dip就是屏幕的宽呢?答案当然是否定的,对于目前主流的屏幕分辨率例如1280x720像素5英寸(xhdpi),1920x1080像素5.5英寸(xxhdpi),360dip经过计算得出恰好占据屏幕。但当碰上某些奇葩屏幕分辨率时例如:1280x768像素,5寸(xhdpi)、1920x1152像素,5寸(xxhdpi),此时360dip分别对应720px与1080px,此时显然达不到屏幕的宽。
由此我们可以得出结论,对于一些主流像素,主流屏幕尺寸,参考xxx手机,适配这些屏幕时,用dip(dp)就能满足我们的需要,但是对于市面上的奇葩分辨率及尺寸,我们得用其它手段适配屏幕(例如:采用百分比的方式适配)。
图片在屏幕中的显示
首先查看这副图片:
缩放比例.png我们可以举个例子:
当我们把一套适配1280x720像素的切图放在xhdpi的drawable文件夹下(其它drawable文件夹没有图片),一个xxhdpi的设备在布局文件中引用了某个切图,假设这个切图的宽占据了360px(1280x720像素屏幕的一半),由于xxhdpi设备获取到的图片在xhdpi下,故系统会自动放大该图片为360px * 1.5 = 540px,此图片刚好占据此xxhpi设备屏幕的一半。同理反过来,一套1920x1080像素的切图同样可以适配xhdpi的屏幕。
但是,需要注意的是,如果要适配例如800x480像素的屏幕,这张图片的显示是达不到我们的预期的。可以举市面上的854x480像素的机型,这些机型往往在4寸到4.5寸之间,通过计算得出ppi在207.3~233.2之间,同属于hdpi。当该机型的某个控件引用了此图片(控件是自适应图片大小),可以通过计算得出实际占据屏幕的像素为:360px * 3/4 =270px。很显然,该图片已经超出屏幕的一半以上了。这种情况最好的解决办法还是增加相应的布局。
适配主流屏幕
我们查看2016年11月与12月的设备分辨率(友盟统计):
android机型分辨率统计.jpg 高宽比例不同的屏幕.jpg由统计我们可知:目前主要的屏幕宽的像素为720p、1080p、480p以及540p,如果需要适配主流屏幕,那么我们需要做的就是适配320dp的屏幕以及360dp的屏幕,对于这种差异,我们可以在layout-w320dp文件夹下创建相应的文件即可。当然由于w320dp主要对应市面上480 * 800的机型,其屏幕比例为3:5,对于高度方向的差异也很明显,如果整个界面是独占式,无法上下滚动,那么我们还需要对高度方向进行相应的调整。
同样,有些平板分辨率则是1920*1200(7英寸),属于xhdpi,但是360dp的宽在屏幕上的只占据720px,显然360dp并不是所有机型的屏幕宽。
如果你的app只针对主流机型的屏幕适配(屏幕宽为360dp,屏幕比例为16:9),那你大可不必创建多种布局文件去适配,但是如果你的目标不仅仅是主流机型,那么就一定需要适配。
需要几套切图
对于现在屏幕设计需要给几套切图,看了大多数博客,总结出的结果是:可以仅给出一套720 * 1280 的图片,放在drawable-xhdpi的资源文件夹下。由于低dpi的设备读取高dpi文件夹的屏幕会按比例缩小,高dpi的设备读取低dpi文件夹的屏幕会按比例变大,看到这也许你会担心:如果低dpi的设备读取这些高dpi文件夹下的图片会增加内存消耗吗?笔者起先也有疑惑,首先将图片按3:4:8的比例分别放置在drawable-hdpi、drawable-xhdpi、drawable-xxhdpi文件夹下,图片的宽高也按3:4:8的比例缩放,我们长宽分别为:27x27:36x36:54x54。我们使用下面这个方法将代码读取到内存中:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image_test);
int byteCount = bitmap.getByteCount();
Log.d("MainActivity", "byteCount: " + byteCount);
我们用xhdpi屏幕机型去执行这段代码,分为三种情况:
- 不删除图片
- 删除drawable-xhdpi文件夹下图片
- 继续删除drawable-xxhdpi文件夹下图片
最后读取的byteCount都为:5184(36*36*4、54*2/3*54*2/3*4、27*4/3*27*4/3*4)
由此我们可以总结出,一套图片放置在相应文件夹下,低dpi的设备读取高dpi文件夹的图片不会导致内存消耗,但是如果你把本该放在drawable-xhdpi图片放在drawable-hdpi文件夹下,那么将会消耗更多内存,甚至会导致ImageView中显示的图片变大;如果反过来呢,本该放在drawable-xhdpi图片放在drawable-xxhdpi文件夹下,那么就会加载的图片比实际预期尺寸要小。
这样做会使得xxhdpi的屏幕读取到的图片效果没有基于1080p设计的效果好,所以有的博主推荐基于1080p的设计,但是这样也会使得apk的空间变大,这当然也不是好事,鱼和熊掌不可兼得,所以还是需要看实际情况再选择哪套图设计。
总结
-
360dp宽是目前主流机型的屏幕宽,但不是绝对的,对于一些奇葩分辨率的屏幕以及平板则不适用。
-
320dp宽是以前主流机型的屏幕宽,同样也不是绝对的,目前市面上同样有该种屏幕的机型,占据比例大概在3.5%,如果要作主流机型适配同样不能忽略。
-
一套720p或者1080p的切图足以应对主流机型的屏幕适配问题,且低dpi的屏幕读取高dpi文件夹下的图片,由于会自动缩小相应比例,所以内存不会比读取相同dpi文件下的图片更耗内存。
感谢以下文章的参考:
http://www.android100.org/html/201505/24/149342.html
http://blog.csdn.net/xiebudong/article/details/37040263/
http://www.cocoachina.com/android/20151030/13971.html
网友评论