Android屏幕适配

    |     2015年4月20日   |   Android UI界面   |     0 条评论   |    1556

图片显示先要分清像素、分辨率和密度。一张图由许多不同颜色的小方格组成,这样的小方格就叫像素,是构成图片的最小单位。像素的物理大小取决于显示设备上一个像素点的荧光点大小;图片文件只记录自己有多少像素、每个像素什么颜色,并不知道自己物理尺寸有多大。例如一张 480×800 的图在电脑显示器上明显比在手机上大,图本身没变,只是手机屏更精细、每个物理像素更小、密度更大。


一、像素、分辨率、密度

分辨率分「图片分辨率」与「物理显示分辨率」。它们都是水平像素点数与垂直像素点数的乘积,也就是像素总数。图片分辨率是文件记录的自身像素数;物理显示分辨率是屏水平与垂直能显示的像素数乘积。有人说分辨率越高图越清晰,这只针对物理尺寸相同的情况——一样的分辨率尺寸可能不同,单比分辨率没有可比性。

密度就是物理设备上单位尺寸里的像素数,密度越大图片显示就越清晰。


二、Android 的长度单位

  • px:像素,终端上的一个物理像素点。例如 480×800 的屏横向 480 个像素、纵向 800 个像素。
  • dip / dp:与物理像素无关,基于屏幕密度的抽象单位,称作设备独立像素,会随密度自动调整大小。
  • sp:比例像素,主要处理字体大小,可根据用户的字体大小首选项缩放。
  • in:英寸,标准长度单位。
  • mm:毫米,标准长度单位。
  • pt:磅,标准长度单位,1/72 英寸。

三、为什么要做屏幕适配

Android 终端的物理尺寸、分辨率类别众多。可能你为一种终端设计的 UI 符合要求,在另一类大小的物理终端上显示就完全不是你想要的。

Android 提供了一套标准,把屏幕分成三类。新建工程后会自动创建三个存放不同分辨率、不同密度 UI 的文件夹:

drawable

三个文件夹下的 UI 对应不同分辨率及密度:

资源目录 屏幕类型 分辨率 密度 尺寸
drawable-hdpi WVGA 480×800 240 大
drawable-mdpi HVGA 320×480 160 中
drawable-ldpi QVGA 240×320 120 小

这三个文件夹只是告诉 Android:你设计的 UI 是针对哪种屏幕分辨率及密度。打开应用时,终端会自动匹配与文件夹里提供的 UI 相近分辨率及密度的图片。

假设终端是 WVGA(密度 240),程序会去抽 drawable-hdpi 下的图,然后用一个物理像素显示一个图片像素——因为你把图放在 hdpi,就是告诉系统 UI 针对 480×800、密度 240,于是不会放大或缩小。当图片密度与屏幕密度相同则不缩放;不同则缩放。


四、实验 1:只放一张 hdpi 图

针对 480×800 的屏设计一张图(分辨率 480×100),分别在不同物理分辨率终端下显示,看会不会不正常。原图:

density

布局文件:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:gravity="center"

    >

    <ImageView

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:src="@drawable/density480800"/>

</LinearLayout>

假设这张图宽 480、高 100,放在 drawable-hdpi,就是告诉 Android 设计意图针对 480×800。它会在 480×800 终端上以一个物理像素显示一个图片像素。若拿到 240×320 终端上,如果系统不处理、仍一对一显示,终端必然显示不下,因为图片像素超过了物理像素个数。注意:这里只设计了一张图并只放在 hdpi,匹配时也就只能匹配这张图。

结果:

WVGA:对比原图,正好显示下,大小相同。

image

HVGA:对比原图,能够显示下,对图片进行了缩小。

image

QVGA:对比原图,能够显示下,对图片进行了缩小。

image


五、实验 2:只放一张 ldpi 图

针对 240×320 的屏设计一张图(分辨率 240×100),分别在不同终端显示。原图:

density-240-320

布局文件:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:gravity="center"

    >

    <ImageView

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:src="@drawable/density240320"/>

</LinearLayout>

这张图专门为 240×320 设计,意图是撑满屏幕宽度,所以 wrap_content 就够,没有考虑其它屏。放在 drawable-ldpi,告诉系统针对 240×320、密度 120。在 240×320 上会一对一显示;若拿到 480×800 上系统不处理,图片像素小于物理像素,就会偏离「充满屏宽」的设计意图。

QVGA:对比原图,正好撑满屏宽。

image

HVGA:虽然设置成 wrap_content,Android 还是进行了放大。

image

WVGA:同上,也会放大。

image

总结:

  • 只要对一种屏幕设计一套 UI,Android 总能通过放大或缩小来适应屏幕、保证设计意图,前提是布局里的单位是 dip。
  • 虽然系统能保证设计意图,实际工作中最好还是多设计几套 UI。实验 2 里放大后的图明显模糊了许多。
  • 如果只想设计一套 UI,最好针对大分辨率终端来设计:缩小比放大的清晰度更好。

六、实验 3:从文件路径读图

上面的图都从 drawable 获取,所以 Android 知道按什么密度处理(放大或缩小)。如果图是从 data/data 或 SD 卡获取,系统会默认把图片当作 160 的基准密度来处理。把实验二的图放入 data/data/cn.com/ 并设到 ImageView 上,本意是充满终端宽度,结果如何?

public class Test4Activity extends Activity {

    private ImageView iv;

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        iv = (ImageView)findViewById(R.id.image);

        iv.setImageDrawable(new BitmapDrawable(BitmapFactory.decodeFile("data/data/cn.com/density-240-320.png")));

}

HVGA 屏下:

image

图片并没有如愿充满屏宽。原因是 Android 把图片密度当作 160 基准密度,而 HVGA 终端密度正好是 160,密度相同不会缩放,于是一对一显示:宽 240 像素的图当然无法充满宽 320 像素的屏。

希望从非 drawable 目录获取的图片也能智能缩放,就要告诉 Android 这张图按什么密度处理:

public class Test4Activity extends Activity {

    private ImageView iv;

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        iv = (ImageView)findViewById(R.id.image);

        BitmapFactory.Options options = new BitmapFactory.Options();

    //设置工厂以120的密度来读取图片文件

         options.inDensity = 120;

        BitmapDrawable image = new BitmapDrawable(BitmapFactory.decodeFile("data/data/cn.com/density-240-320.png",options));

        //设置图片在终端中以终端本身的密度来显示图片

         image.setTargetDensity(getApplicationContext().getResources().getDisplayMetrics());

        iv.setImageDrawable(image);

}

最终效果,HVGA 屏下:

image

结束:Android 中长度单位最好使用与物理像素无关的逻辑像素 dip,这样系统就能自动适应不同屏幕、保持设计意图。图片大小的转换是基于密度,与屏幕分辨率和尺寸大小无关。

一句话总结:布局用 dp/dip,图片按 hdpi/mdpi/ldpi 分桶;从文件读图时要自己设 inDensity 和 targetDensity,系统才会按密度缩放。

转载请注明来源:Android屏幕适配
本文链接地址:https://ai.zhousir.top/?p=480

上一篇:

下一篇:

回复 取消