为了查看方便,特意贴一段 Google API 文档:http://developer.Android.com/intl/zh-cn/guide/practices/screens_support.html
近期做些关于手机适配的工作。
下面来总结一下,希望可以对大家有帮助,本人能力有限,如果有解释失误的地方,请务必帮忙指出,谢谢。
首先引入几个概念。
PPI : Pixels Per Inch的缩写简称,表示的是每英寸显示屏所拥有的像素(pixel)数目。
DPI : Dots Per Inch , 最初用于衡量打印物上每英寸的点数密度,就是说你的打印机可以在一英寸内打多少个点。
DPI用来表示输出设备的输出精度,如打印机,显示器
DPI表示的是 像点/英寸(每英寸长度上有多少个打印点或像点)
PPI用来表示输入设备的输入精度,如扫描仪,数码相机
PPI表示的是 像素/英寸(每英寸长度上有多少个像素)
显然,在谈到Android设备屏幕时,用DPI 比较合适,官方文档中也是用DPI来说明的。当然,如果有人说成PPI,也并不妨碍理解,只是这种说法不太准确。
关于如何计算DPI ,下面我们拿三星S3为例。
根据三星官网给的 信息:
The S III's HD Super AMOLED display measures 4.8 inches (120 mm) on the diagonal. With a 720×1280-pixel (720p) resolution, its pixel per inch (PPI, a measure of pixel density) is a relatively high 306。
我们可知:分辨率为 720x1280(高宽比为16:9) , 4.8英寸 , 306dpi。
那么,这个dpi是如何计算出来的呢?
由于对角线长为4.8英寸,我们要计算对角线上一共有多少像素点。
进而求每英寸的像素点个数,即 (在Android中,大家把PPI 和 DPI 看成一个东西即可)
这么计算后可知,三星S3的DPI = 306. 即,该手机每英寸有306个像素点。
下面再介绍Android中非常重要的几个概念。
dp (或 dip) , Density-Independent Pixels. 按照字面意思:密度无关的像素点。
那么,何为Density?
先了解一下屏幕的级别:
屏幕级别 |
屏幕密度DPI |
密度比值 |
像素量/英寸 |
通常的分辨率 |
ldpi |
120 |
0.75 |
120 |
240x400 |
mdpi |
160 |
1 |
160 |
320x480 |
hdpi |
240 |
1.5 |
240 |
480x800 |
xhdpi |
320 |
2 |
320 |
|
xxhdpi |
480 |
3 |
480 |
|
在这里,Android将mdpi 下 px:dp = 1:1换算。将其设置为baseline后,它的density为1.其他手机的density就能轻易算出来。
(可能有人会问为何dp是这么定义的?因为,Android历史第一部手机:T-mobile G1 就是这种分辨率)
如果不是以上给出的这些通常的分辨率,那么我们如何确定它的DPI呢?
比如手机基伍A800 ,5.0英寸 , 分辨率为540x960 , 根据公式计算得出 DPI = 220,
那么,就近原则,它的屏幕密度被认为是240dpi , density = 1.5 , 找的相关资源图片在 drawable/hdpi 文件夹下。
如果想利用sw
Step1:
可以通过adb命令来快速获取手机的屏幕参数:
adb shell dumpsys window displays
(this command can get all display information, include resolution and dpi.)
通过该命令,我们可以取得手机的dpi(dot per inch),以及分辨率等。
Step2:
dp和px的换算公式: dp = (px * 160)/ dpi
注:这里的dpi是归化后的dpi,并非是真实的dpi。基伍A800的真实dpi为220dpi,归化后的dpi只有这几种:
Android会取就近的dpi值,220离240最近,所以基伍A800的机器dpi为240.
拿A800 为例,屏幕分辨率为 960*540 ,dpi 为 240。
因为我们要计算sw
所以该N的计算的公式: dp = (540*160)/ 240 = 360.
如果为480*800 、 480*854 dp = 480*160 / 240 = 320.
所以,A800在适配的时候,找到的dimen.xml是Res/values-sw360dp/dimen.xml
补充说明:
Android在适配的时候会找小于等于N的资源。
比如A800,其smallestWidth的N=360.如果你不是将资源放在Res/values-sw360dp/dimen.xml中,
而是放在Res/values-sw340dp/dimen.xml中。也不影响它正确适配。只是不够精确罢了。
如果某款手机的smallestWidth的N=300 ,都适配不到的情况下,Android将默认去res/values/dimen.xml中寻找。
为了防止crush,请在默认的dimen.xml中也配置上相应参数。
2015-06-25 再次补充:
在机型适配的时候,还会碰到更加棘手的问题。
比如:
三星S2的分辨率:480*800
小黄蜂hyf9300的分辨率:480*854
此时,小黄蜂的分辨率在竖直方向的高度比S2多了54像素点高度,而上述的sw
两款手机的sw均为320dp,不能很好的区分两款手机。此时该如何做呢?
谷歌在3.2以后推荐使用以下这几种方法来进行适配:
其中,h
根据英文描述我们可以知道,此处的N和手机的orientation有关。
横竖屏切换时,N也随着变动,并且N值是指的是UI可用高度。这个地方的可用高度不包含systemUI占用的高度,诸如状态栏等。
也就是说,当你计算出竖直方向的高度后,还要减去系统UI所占用的高度(包括状态栏和titlebar等)。
除非你的应用已经设定orientation是固定的,这样你才可以放心地使用该方法来处理机型适配问题。
了解了上面的知识后,我们开始为下面3款机型适配。(下面所说的h
机型 |
分辨率 |
全屏高度h |
三星S2 |
480*800 |
N = 800*160/240 = 533.33dp |
小黄蜂 |
480*854 |
N = 854*160/240 = 569.33dp |
A800 |
540*960 |
N = 800*160/240 = 640dp |
由于我们团队开发的应用只有状态栏是属于systemUI,所以该N还得减去状态栏的高度为25dp。
机型 |
分辨率 |
可用高度h |
三星S2 |
480*800 |
N = 533.33 - 25 = 508.33dp |
小黄蜂 |
480*854 |
N = 569.33 - 25 = 544.33dp |
A800 |
540*960 |
N = 640 - 25 = 615 dp |
该h
比如小黄蜂手机打开的应用检测出其可用高度为544.33dp,
先查找对应的文件夹即:values-h544.33dp/dimen.xml,如果没有找到,那么向下匹配。
实在找不到,最后才去values/dimen.xml中默认匹配。
所以,最后在保证可以查找到并且允许状态栏等高度小幅度变化的情况下,我们在代码中设定其高度为:
机型 |
分辨率 |
h |
对应的适配文件 |
三星S2 |
480*800 |
N = 500dp |
values-h500dp/dimen.xml |
小黄蜂 |
480*854 |
N = 540dp |
values-h540dp/dimen.xml |
A800 |
540*960 |
N = 610dp |
values-h610dp/dimen.xml |
当然,最后还是别忘了在values/dimen.xml文件中加入默认的配置,以防在找不到的情况下发生crush。