为了让程序有更好的屏幕适配能力,在指定控件和布局大小的时候最好使用match_parent和wrap_content,尽量避免控件的宽和高设定一个固定值。不过在实际的开发当中,仅仅使用match_parent和wrap_content已经无法满足需要,这时需要给控件的宽和高指定一个固定值。常用的指定宽高的固定大小的单位有:px、pt、dp和sp。
px和pt的窘境:
px是像素的意思,即屏幕中可以现实的最小元素单位。pt是磅数的意思,1磅等于1/72英寸,一般pt都会作为字体的单位来使用。但是由于手机的分辨率各不相同,一个200px宽的按钮在低分辨率的手机上可能将占尽满屏,而到了高分辨率的手机上只占据屏幕的一半。修改 activity_main.xml 中的代码,如下所示:
<span style="font-family:Microsoft YaHei;font-size:14px;"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/button"
android:layout_width="200px"
android:layout_height="wrap_content"
android:text="Button"
/>
</LinearLayout></span>
这里通过修改android:layout_width属性将按钮的宽指定为200px,然后运行程序,效果图如下图所示:
接着创建一个 240*320 像素的低分辨率模拟器,在这个模拟器上重新运行程序,效果如下图所示:
可以明显看出,同样 200px 宽的按钮在不同分辨率的屏幕上显示的效果是完全不同的,pt 的情况和 px 差不多,这导致这两个单位在手机领域上面很难有所发挥。
dp和sp的优势:
dp 是密度无关像素的意思,也被称作 dip,和 px 相比,它在不同密度的屏幕中的显示比例将保持一致。sp 是可伸缩像素的意思,它采用了和 dp 同样的设计理念,解决了文字大小的适配问题。
Android 中的密度就是屏幕每英寸所包含的像素数,通常以 dpi 为单位。比如一个手机屏幕的宽是 2 英寸长是 3 英寸,如果它的分辨率是 320*480 像素,那这个屏幕的密度就是 160dpi,如果它的分辨率是 640*960,那这个屏幕的密度就是 320dpi,因此密度值越高的屏幕显示的效果就越精细。
重新修改activity_main.xml 中的代码,设置android:layout_width中的属性为200dp,并运行在不同分辨率的模拟器上,结果显示按钮在屏幕上所占大小的比例几乎是相同的。效果如下图所示:
度量单位的换算公式:
在android源码包TypedValue.java中,我们看如下函数:
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;
}
该函数功能:是把各单位换算为像素。
metrics.density
:默认值为DENSITY_DEVICE / (float) DENSITY_DEFAULT;
metrics.scaledDensity:
默认值为DENSITY_DEVICE / (float) DENSITY_DEFAULT;
metrics.xdpi:
默认值为DENSITY_DEVICE;
DENSITY_DEVICE
:为屏幕密度
DENSITY_DEFAULT:
默认值为160
注明:sp换算成px数y的公式为:
y = x * scaledDensity
这里的 scaledDensity 获取方式为getResources().getDisplayMetrics().scaledDensity。