这节课将会学习如何通过不同的资源以及独立的测量单位来支持不同的屏幕密度。

使用密度独立的像素单位

你必须要避免这么一个陷阱:在设计布局时,使用了绝对的像素单位来定义距离及尺寸。通过像素来定义布局的尺寸是个问题,因为不同的屏幕含有不同的像素密度,所以在不同的设备上使用同一像素长度会造成不同的物理尺寸。因此在指定尺寸时,应该总是使用dp或者sp为单位。dp是一种密度独立的像素单位,在160dpi时与像素的物理尺寸正好吻合(也就是说160dpi的屏幕dp正好等于sp)。sp同样也是一种基准单位,但是它一种可伸缩的文本尺寸单位,所以应当在定义文本尺寸时使用该单位(绝不要在布局上使用该单位)。

比如说,在指定两个View之间的空隙时,应该使用dp,而不是px:

<Button android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/clickme"
    android:layout_marginTop="20dp" />

在指定文本大小时,总是使用sp:

<TextView android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="20sp" />

提供备选位图

因为Android运行于种类繁多的设备上,所以应当为普遍的密度范围提供相应的位图资源:low, medium, high及extra-high密度。这有助于提升所有屏幕密度的物理效果及性能。

为了产生这些位图,应当通过原生资源生成多种密度的图像:

  • xhdpi: 2.0
  • hdpi: 1.5
  • mdpi: 1.0 (基准线)
  • ldpi: 0.75

这意味着如果为xhdpi的设备生成了200x200的图像,那么应该为hdpi提供的尺寸为150x150,mdpi为100x100,ldpi为75x75。

然后将这些文件分别放入适当的目录下,在运行时,系统会根据当前的屏幕密度自动选择正确的位图:

MyProject/
  res/
    drawable-xhdpi/
        awesomeimage.png
    drawable-hdpi/
        awesomeimage.png
    drawable-mdpi/
        awesomeimage.png
    drawable-ldpi/
        awesomeimage.png

接下来,在任何时候引用@drawable/awesomeimage时,系统会基于屏幕的dpi选择合适的位图图像。

最后将启动图标放入到mipmap/文件夹下:

res/...
    mipmap-ldpi/...
        finished_launcher_asset.png
    mipmap-mdpi/...
        finished_launcher_asset.png
    mipmap-hdpi/...
        finished_launcher_asset.png
    mipmap-xhdpi/...
        finished_launcher_asset.png
    mipmap-xxhdpi/...
        finished_launcher_asset.png
    mipmap-xxxhdpi/...
        finished_launcher_asset.png

Note: 应当将所有的启动图标放入到res/mipmap-[density]/文件夹下,而不是drawable/文件夹中,这样可以确保桌面APP使用了最佳的分辨率图