一、定义
dp值主要用来描述控件的大小,确保在不同的设备屏幕下,所展示的控件大小基本一致。
sp值则专门用来设置字体的大小。
二、分析
我们参考TypeValue类中的applyDimension方法来分析sp与dp的区别。
这个方法是用来将对应的参数值转换为px值的。
public static float applyDimension(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;
}
其中,dp(dip)的转换公式为value*metrics.density。而sp的转换公式为value*metrics.scaledDensity。
所以sp与dp的差别,事实上就是density与scaledDensity的区别。
我们再来看scaledDensity的注解:
/**
* A scaling factor for fonts displayed on the display. This is the same
* as {@link #density}, except that it may be adjusted in smaller
* increments at runtime based on a user preference for the font size.
*/
public float scaledDensity;
这个值实在density的基础上,根据用户对字体偏好的设置进行了微调。
所以,当用户设置字体为默认值的时候,density与scaledDensity是相等的。
三、具体测试
我这里使用华为MT7进行具体真机的测试。
对应的density=3.0,
字体默认为:标准,scaledDensity=3.0。这与density相等。
改变字体偏好:
小:scaledDensity=2.5500002,大致是标准的0.85
大:scaledDensity=3.4499998,大致是标准的1.15
超大:scaledDensity=3.8999999, 大致是标准的1.3
特大:scaledDensity=3.90003,大致也是标准的1.3
特大字体与超大字体差别并不大,具体到显示上也的确如此。此处不知为何华为要加设一个特大字体,而事实上和超大也没多大差别。
再使用虚拟机模拟测试,这个虚拟机的density=3.5
字体默认为:正常,scaledDensity=3.5。
小:scaledDensity=2.9750001,大致是标准的0.85
大:scaledDensity=4.025,刚好是标准的1.15
超大:scaledDensity=4.549997, 大致是标准的1.3
虚拟机中没有特大选项。
四、结论
由此我们也可以推知:
- 系统对字体的调整,应该是在dp值的基础上按照一个比例来计算得出,大致是15%一个档。具体的算法,本人并未仔细推敲,微小的差距应该是此值按float存储,无法除净的原因
- 当字体选择为标准值时,sp与dp值是相通的,而选择其他是会有对应缩放。
- 可以推知,当我们希望某个自定义的空间更具字体大小作出对应缩放的时候,可以尝试使用sp来设置其大小。
- 如果我们不使用sp而是使用dp来设置字体大小时,系统设置中的字体偏好就无法影响到我们应用中的文字显示大小了。
以上为个人观点,如有错误,欢迎留言指正。