android多分辨率像素指定

efbb 9年前

开发手机android应用,必定面临多屏幕支持问题。你一定希望应用程序能在不同的大小的手机上都能很好的展现漂亮的布局和细腻的图片。本文将介绍如何做到这一点。

先看看没有支持多分辨率程序的效果。下面是同一个程序运行在两个不同规格的屏幕上的截图。右边这个似乎不可接受。

  android多分辨率像素指定               android多分辨率像素指定

     图1:480*800,3.5寸屏                       图2     480*800,5寸屏

 

 

支持多分辨率后的效果

 

android多分辨率像素指定                     android多分辨率像素指定

    图3 480*800,3.5寸屏                          图4  480*800,5寸屏

   

  

   我们先来了解一些屏幕的基本概念:

    物理尺寸: 就是所说的几寸的屏幕,代表屏幕对角线的长度,比如3.5寸、3.7寸、4寸、7寸等。

    分辨率: 是屏幕总共能显示的像素数,通常我们都说几百×几百,比如240*320,320*480,480*800等

    像素密度(DPI):DPI的全称是dots per inch,每英寸点数.

    这三个参数,任两个确定后,第三个量就是确定了。公式为:某边的分辨率(总像素数)= 该边物理尺寸(单位是英寸) × 像素密度。

    比如一个3.5寸的屏幕,分辨率为480×800,那么密度为开方(480^2+800^2)/3.5 约等于为194。屏幕大小和屏幕像素密度是可以独立的,不是说一个5寸屏的密度就一定是hdpi。

 

   手机屏幕分类

   按密度分为:低密度(ldpi),中密度(ndpi),高密度(hdpi),超高密度(xhdpi)。

   按尺寸分为: small, normal, large, and xlarge

   android多分辨率像素指定
                                       图5

  

   大部分手机集中在normal,hdpi这一栏。可见多屏幕适配的重点在这里。

   android多分辨率像素指定
                图6

 

    适应多屏幕要分别考虑界面布局和图片资源两个方面(一体两面)。

    布局上不考虑多屏幕尺寸,可能出现控件没对齐,尺寸超出屏幕外等。

    图片上不考虑多屏幕密度,可能出现图片看起来大小不合适,比较模糊等。

    到底要考虑布局,还是考虑图片,或者两者同时考虑由应用决定。我个人觉得,一般布局要考虑得多一些。如果应用有很多图片,而且对现实细腻程度要求很高,才考虑图片。

    但是,所谓考虑多屏幕适应,并非要为没每种屏幕大小提供一个布局文件,也并非要为每种屏幕密度提供一套位图,按大的分类提供就可以了。(如果要那样做也没错,但将付出巨大的维护代价)

    例 如,一般为所有尺寸是normal的屏幕提供一套布局,尽管normal里又分很多种(看 图 5),但一般android都能很好的适应。也可以为所有密度是hdpi的屏幕提供一套图片,尽管hdpi也分很多种(看 图 5),但一般android都能很好的适应。

    另 外一方面,即使按大的分类考虑布局文件,也并非要为每个布局文件都创建多个版本。只有布局文件中用数值定义了控件大小(无论你用的单位是px还是 dip),才需要考虑写多个布局文件。如果是用fill_parent,wrap-contents等方式则用一个布局文件就可以了,把它放在 layout目录里。

    根据密度你仅需要提供drawable下的位图文件,如果你使用Xml来定义shape,colors或者其他drawable的资源,你就应该放到"drawable/"默认目录下

    注意:实际开发中,为了适合多屏幕,又减少维护量。mdpi,hdpi内一般要放东西, ldpi则可放可不放。当要用到ldpi时,它从hdpi里去取并缩放。效果也不错。

 

   Android如何选择适合当前屏幕的资源呢?

    选取规则如下:

   (Drawabe和Drawabe-mdpi等价)

   (Layout和layout-normal等价)

    1.基于当前屏幕的尺寸和密度,系统会在最匹配的的设备配置下的资源目录寻找。

    2.如果没有可用的匹配资源,系统会使用默认资源等比放大或缩小以匹配当前屏幕的大小和密度。 这里的默认资源是没有后缀的。

    例如对于HVGA,large screen,ldpi的一块屏幕,系统会优先找res/layout-large,res/drawable-ldpi下的资源。如果没有,就使用res/layout和res/drawable

    3.如果系统想找一个ldpi(低密度)的资源,但找不到。那么系统会等比缩小hdpi的资源,为什么不寻找mdpi呢?因为系统对于hdpi更容易缩放,它的系数为0.5,相比mdpi的0.75来说。0.5的的性价比更高。

简要的概述下就是如果没有匹配的系统会使用默认的资源,如果连默认下都没有放资源,那么系统就没有资源可用啦。

    但我实际测试有些出入,如果只在drawable-hdpi里放图片,其它地方都不放,然后用mdpi的手机去测试,按道理它先找drawable,没找到就没则了,但图片在界面上还是显示了,说明它找到drawable-hdpi里去了,Why?

 

   多屏幕适应黄金法则

    1.XML Layout中最好控件大小最好用Wrap_content, fill_parent。

    2.如果必须使用数字来到定义控件大小,最好用DIP。文字大小用sp

    3.不要用px定义控件,文字大小。

    4.不要用绝对布局

    5.为不同密度手机,提供不同分辨率图片,如果你发现一套图片在另外一种密度的手机上表现都还不错,就不需要为那种密度提供额外的图片。

    6.用模拟器测试不同分辨率

    7.需要注意的地方, 以上设置适用于android3.2以下的版本。

 

   图片设计的一些建议

   图标建议

   android多分辨率像素指定

   其他图片建议

    先为主流的中精度屏幕(HVGA)设计一套icon,确定图片的像素尺寸。

    为高精度屏幕将图片放大到150%,为低精度屏幕将图片缩小至75%。即L(0.75) - M (1) - L(1.5)

 

 

   开发适应多屏幕应用程序的基本思路

    首先应当明确应用希望支持几种分辨率设备;并非越多越好。虽然理论上建议大家支持所有的屏幕设备,但这确实比较麻烦而且很容易出错。我们一般最好把手机和平板分时两大类来发布2个APK这样的效果会更好。 

    其 次,需明确哪些资源文件在不同分辨率的设备存在显示问题。对于显示有问题的,需要重新准备与相应分辨率设备适配的资源文件和页面布局文件。并非一来就要把 想支持的各种尺寸和密度的屏幕对应的目录建立起来. 先按某种尺寸和密度开发。然后在不同的屏幕上测试,只针对有问题的布局文件和图片提供另外的支持。

对于布局,如果书写得当,你会发现只需要一个放在layout里布局文件将可以在各种尺寸的屏幕上很好的显示。如何书写得当?请看“多屏幕适应黄金法则”

    对于图片,在不同密度的屏幕上有可能会产生缩放。但如果变形不是很严重,也还是可以接受。毕竟用多张图片会增加apk包的大小。

    总之,尽量用一套布局和图片去适应多屏幕。实在很难看,才考虑多个布局和图片。要记住,这些东西越多,维护起来越麻烦。

    我 在实际开发中,一般先按照WVGA标准,480*800,normal screen,240dpi,3.5寸建立一个模拟器。布局文件目录先只建layout一个,图片也先放到drawable-hdpi下,然后在上面调试 UI。觉得没问题了,才建立其他尺寸和密度的模拟器来看效果,只对需要调整的部分重新设计布局文件和图片,并放到合适的目录下。

 

布局实例

AndroidManifest.xml中提供新的一个元素<supports-screens>用于支持多屏幕机制。

<supports-screens

          Android:largeScreens="true"   是否支持大屏

          Android:normalScreens="true"  是否支持中屏

          Android:smallScreens="true"   是否支持小屏

          Android:anyDensity="true"     是否支持多种不同密度

/>

 

选定基准测试屏幕,例如在模拟器上设置WVGAnormal screen, hdpi480*8003.5寸为activity编写布局文件:preview_photo.xml。 因为是中屏,用res/layout目录就可以了。不要用绝对布局,尽量用fill_parentwrap_contents指定控件和容器大小,实在没法了,才用dip指定控件大小。

 

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

<FrameLayout

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

    android:id="@+id/previewPhotoLayout"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

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

        android:orientation="vertical"

        android:gravity="center_vertical"

        android:layout_width="fill_parent"   

        android:layout_height="fill_parent"

        >

        <LinearLayout

            android:gravity="center_horizontal"

            android:orientation="horizontal"

            android:layout_width="fill_parent"

            android:layout_height="fill_parent"

            android:layout_marginBottom="5.0dip"                       

            android:layout_weight="1.0"

            >         

            <ImageView

                android:id="@+id/imageView1"

                android:layout_width="400dip"

                android:layout_height="153dip"

                android:layout_weight="1.0"

                android:background="#ffffffff"

                android:src="@drawable/icon"

            />

            <ImageView

                android:id="@+id/imageView2"

                android:layout_width="400dip"

                android:layout_height="153dip"

                android:layout_weight="1.0"

                android:background="#ffffffff"

                android:layout_marginLeft="5.0dip"

                android:src="@drawable/icon"

            />                    

        </LinearLayout>

        <LinearLayout

            android:gravity="center_horizontal"

            android:orientation="horizontal"

            android:layout_width="fill_parent"

            android:layout_height="fill_parent"

            android:layout_weight="1.0"

            >

            <ImageView

                android:id="@+id/imageView3"

                android:layout_width="400dip"

                android:layout_height="153dip"

                android:layout_weight="1.0"

                android:background="#ffffffff"

                android:src="@drawable/icon"

            />

            <ImageView

                android:id="@+id/imageView4"

                android:layout_width="400dip"

                android:layout_height="153dip"

                android:layout_weight="1.0"

                android:background="#ffffffff"

                android:layout_marginLeft="5.0dip"

                android:src="@drawable/icon"

            />              

        </LinearLayout>

    </LinearLayout>

</FrameLayout>

 

  测试,效果如图

  android多分辨率像素指定

再切换到小屏幕测试,用模拟器创建一块屏幕QVGAsmall screen, 240*480, 2.8寸,显示如下,looks good。就不再需要提供layout-small

    android多分辨率像素指定

再切换到大屏幕。用模拟器创建一块屏幕:WVGAlarge screen, mdpi, 480-800 5

显示如下, very ugly, 需要新写一个布局文件。

    android多分辨率像素指定

于是再写一个布局文件preview_photo.xml放在res/layout-large下:注意仅仅修改了ImageViewandroid:layout_height这个属性。可见,使用了数字定义控件大小,要增加不少维护工作量。

 

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

<FrameLayout

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

    android:id="@+id/previewPhotoLayout"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

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

        android:orientation="vertical"

        android:gravity="center_vertical"

        android:layout_width="fill_parent"   

        android:layout_height="fill_parent"

        >

        <LinearLayout

            android:gravity="center_horizontal"

            android:orientation="horizontal"

            android:layout_width="fill_parent"

            android:layout_height="fill_parent"

            android:layout_marginBottom="5.0dip"                      

            android:layout_weight="1.0"

            >         

            <ImageView

                android:id="@+id/imageView1"

                android:layout_width="400dip"

                android:layout_height="240dip"

                android:layout_weight="1.0"

                android:background="#ffffffff"

                android:src="@drawable/icon"

            />

            <ImageView

                android:id="@+id/imageView2"

                android:layout_width="400dip"

                android:layout_height="240dip"

                android:layout_weight="1.0"

                android:background="#ffffffff"

                android:layout_marginLeft="5.0dip"

                android:src="@drawable/icon"

            />                    

        </LinearLayout>

        <LinearLayout

            android:gravity="center_horizontal"

            android:orientation="horizontal"

            android:layout_width="fill_parent"

            android:layout_height="fill_parent"

            android:layout_weight="1.0"

            >

            <ImageView

                android:id="@+id/imageView3"

                android:layout_width="400dip"

                android:layout_height="240dip"

                android:layout_weight="1.0"

                android:background="#ffffffff"

                android:src="@drawable/icon"

            />

            <ImageView

                android:id="@+id/imageView4"

                android:layout_width="400dip"

                android:layout_height="240dip"

                android:layout_weight="1.0"

                android:background="#ffffffff"

                android:layout_marginLeft="5.0dip"

                android:src="@drawable/icon"

            />              

        </LinearLayout>

    </LinearLayout>

</FrameLayout>