一、基本概念
布局文件中,宽度输入数字之后会弹出一些单位供选择:px、dp、sp、pt、in、mm
px:对应的是实际像素点,1px就是1个像素格。手机尺寸1080x1920,就是说手机有1080x1920个像素点。
dp:市面上有很多机型,它们的尺寸都是不固定的。为了避免不同机型的UI表现差异过大,可以用dp。dp和px之间的换算公式:px = dp * density。(不同的设备density也可能不一致)
打个比方:
设备A宽度为320,设备B宽度为640。
1. 布局一个320px的图像,在设备A上可以占满宽度,设备B上只能占一半宽度。
2. 布局一个320dp的图像,设备A的density为1,在设备A上占320个像素,占满宽度;设备B的density为2,在设备B上占640个像素,占满宽度。
sp:原理与dp类似。这个单位主要用来设置字号,在系统设置中调整字号大小,1sp对应的像素数量会发生变化。换算公式可以理解为 px = sp * density * scale。
pt: 是一个实际单位,1pt = 1in / 72
in: 实际单位的英寸。1in = 2.54cm=25.4mm
mm: 实际单位的毫米。
二、各单位间转换
通过resources.getDimension
最终可以走到以下这段代码:
public static float applyDimension(@ComplexDimensionUnit int unit, float value,
DisplayMetrics metrics)
{
switch (unit) {
case COMPLEX_UNIT_PX:
return value;
case COMPLEX_UNIT_DIP:
return value * metrics.density;
case COMPLEX_UNIT_SP:
return value * metrics.scaledDensity;
case COMPLEX_UNIT_PT:
return value * metrics.xdpi * (1.0f/72);
case COMPLEX_UNIT_IN:
return value * metrics.xdpi;
case COMPLEX_UNIT_MM:
return value * metrics.xdpi * (1.0f/25.4f);
}
return 0;
}
这段代码就是各个单位之间的转换公式。
DisplayMetrics中的一些重要参数,我们只要用就可以了。
density
densityDpi
scaledDensity
xdpi
ydpi
先简单理解下它们的概念.
densityDpi
也就是屏幕密度,即每英寸的屏幕中包含的像素数量。这个值越高,画面就越清晰。标准的值是160。
density
逻辑密度。这个值从逻辑概念上不太好理解。它的计算公式是density = DENSITY_DEVICE / (float) DENSITY_DEFAULT;
也就是设备的屏幕密度除以默认屏幕密度(160)。标准的屏幕密度为160,它的密度比例就是1,即1个dp就等于1个像素。如果你手机的densityDpi为320,则它是标准屏幕密度的两倍(320 / 160 = 2),则density = 2,表示1个dp就等于2个像素。
scaledDensity
字体比例。在ResourcesImpl.java
中找到了一句代码mMetrics.scaledDensity = mMetrics.density * (mConfiguration.fontScale != 0 ? mConfiguration.fontScale : 1.0f);
可以看出,它的值其实就是逻辑密度*字体缩放系数。这个字体缩放系数是由系统设置中的字体大小控制的。所以一般这个单位只用于设置字号。
xdpi
水平方向上的屏幕密度
ydpi
垂直方向上的屏幕密度
我们再回到前面的resources.getDimension
,这个方法返回的是像素值,单位是px。
所以:
px * 1 = px
dp * density = px
sp * scaledDensity = px
xdpi是水平方向上的屏幕密度,也就是水平方向上1英寸内的像素个数,所以:
in * xdpi = px
1pt = 1in / 72, 所以:
pt * xdpi / 72 = px
1in = 2.54cm = 25.4 mm, 所以:
mm * xdpi / 25.4 = px
三、getDimension、getDimensionPixelOffset、getDimensionPixelSize有什么区别?
第一次用的时候非常迷惑,这三个方法有什么区别?
还以为是返回结果的单位不一样,但是看注释,返回结果单位都是px。
这三个方法最终都会调用applyDimension(),将不同单位的数值换算成px单位,换算结果可能会有小数,那这个小数怎么处理呢?
方法名 | 返回值 | 备注 |
getDimension() | 返回float型px值 | 精确 |
getDimensionPixelOffset() | 返回int型px值 | 小数截断 |
getDimensionPixelSize() | 返回int型px值 | 四舍五入 |
目前没有觉得这个三个方法有什么特别的区别,按需选用吧。