Android屏幕适配

jopen 10年前

android的屏幕适配一直是开发者头疼的问题,因为android的设备大小不一,而且屏幕显示效果也不相同,如何对android进行屏幕适配是一个很大的挑战,为了应对不同的情况,需要仔细研究android对不同屏幕的定义。看过学渣的这篇博客,希望大家对屏幕适配有一个基本的了解。

1 android的屏幕大小

android的屏幕有大有小,为了对不同大小屏幕的设备提供最好的体验,需要对不同大小的设备进行不同的设计,首先遇到的问题就是android对屏幕大小的区分。

android的屏幕问题在官网有详细说明,,作为一名学渣,需要细细研读,首先android把屏幕分为四种大小:small,normal,large,xlarge,这四种屏幕首先是直观的区分,即对设备的对角线用尺子量一下,用英寸做单位进行区分,比如学渣用的红米就是4.7英寸,属于normal,具体分类如图1所示:

20140609113244687.png

图1 android屏幕大小区分

如果你的程序获知android设备屏幕后,根据大小不同可以采用不同的布局方案,但是我们写程序时,进行布局时,不可能用英寸进行布局,先假设我们使用像素(px)进行布局,但是这里会遇到一个问题,这里需要介绍新的term,请看2。。。。。

2 屏幕的分辨率和密度

 这里遇到的问题需要看几个术语,android官网上去后有几个术语介绍,学渣先为大家介绍分辨率和密度

        分辨率(Resolution):The total number of physical pixels on a screen. 即一个设备的物理像素,如1280*720,大家可以自己计算。

    密度(Screen density):The quantity of pixels within a physical area of the screen; usually referred to as dpi (dots per inch).一般我们的密度的单位是像素数目/平方英寸,但是这里推荐了一个新的密度表示方法,就是每英寸的像素数目(dpi)。我们以后用到的密度就是这个dpi

     android里用分辨率和密度这两个域来记录设备的真实尺寸,采用密度的主要原因(学渣猜的)应该是“去英寸化”,即在程序中不要出现英寸这个单位,因此用密度和分辨率这两个值可以保存设备的真实尺寸。

    对于一个程序而言,它可以获取到屏幕的分辨率和尺寸,进而密度=分辨率/尺寸,可以算出尺寸,在android里,获取密度尺寸可以参考这里我们这里用一个小程序来求两个设备的分辨率和密度。学渣定义了两台avd,尺寸都是4.7英寸,设备1的分辨率为800*1280,设备2的分辨率为480*800,测试代码如下:

    package com.example.testscreen;                import android.os.Bundle;        import android.app.Activity;        import android.util.DisplayMetrics;        import android.view.Menu;                public class MainActivity extends Activity {            @Override            protected void onCreate(Bundle savedInstanceState) {                super.onCreate(savedInstanceState);                setContentView(R.layout.activity_main);                                 DisplayMetrics metrics = new DisplayMetrics();                 getWindowManager().getDefaultDisplay().getMetrics(metrics);                                  //得到设备的分辨率,即宽和高的像素数目                 int height = metrics.heightPixels;                 int width = metrics.widthPixels;                                  System.out.println("the height is "+height +" the width is" + width);                                  //得到设备的密度                 int density = metrics.densityDpi;                 System.out.println("the density is " + density);                            }        }  

设备1的输出是:

    06-09 00:10:17.188: I/System.out(2041): the height is 1184 the width is768        06-09 00:10:17.188: I/System.out(2041): the density is 320  
设备2的输出是:

    06-09 00:45:35.085: I/System.out(2088): the height is 736 the width is480        06-09 00:45:35.085: I/System.out(2088): the density is 213  

    从两个设备的输出可以知道,其实学渣是定义了两个4.7英寸的avd,但是有着不同的分辨率,(android里有底部栏,看起来有点不一样),这两个例子说明了一个问题:相同大小的手机,可以有不同的分辨率,进而就有不同的密度喽,(因为密度=分辨率/大小)。

3 程序判断屏幕大小

      每个程序都需要判定屏幕的大小,进而选择合适的布局(后面会说),如何判定大小(设备的真实尺寸,可以理解为设备对角线的英寸数)呢,就根据2所提到的两个参数来判断,一个是分辨率,一个是密度,用设备1而言,知道height是1184像素(px),其密度为320dpi(像素/英寸),则高度的具体值就是1280/320=4(英寸),宽度为800/320=2.5 ,用勾股定理算出对角线的长度,(学渣这里没有细算)再和图1匹配,得到这个设备的屏幕大小尺寸。

      屏幕大小判定之后,首先需要在mainfest声明支持的屏幕大小,如:

    <supports-screens android:largeScreens="true" />  

             要想要好的用户体验,程序可以根据不同的大小选择不同的布局,android官方文档里也提到了,可以对不同的大小,设置不同的layout,如res/layout-large就是large屏幕时所采用的布局。

    官方文档里有这么几句话要注意:Beginning with Android 3.2 (API level 13), the above size groups are deprecated and you should instead use the sw<N>dp configuration qualifier to define the smallest available width required by your layout resources. For example, if your multi-pane tablet layout requires at least 600dp of screen width, you should place it inlayout-sw600dp/.即对于3.2以上的,直接采用dp(dp相当于一种程序中的英寸大小)进行判断屏幕的宽度,进而选择不同的布局,如/res/layout-sw600dp,就是宽度要求是600dp以上的我们就选择这个布局。不过意思和small,large等一样,只不过把大小换成了具体的数字。

3 去英寸化 

   上面我们提到了去英寸化,如何让一个程序能够很好的显示大小呢,似乎可以采用像素?但是这是完全不可以的。先举一个简单的例子说明像素的缺陷,还是采用上述的设备1和设备2进行测试,我们在设备1和设备2都定义一个button,宽度和高度都为200px(像素),效果如图2所示:

20140609131337421.png

图2 相同大小的手机,相同的像素大小的button

      其实这个结果一点也不意外,这是因为两个button的像素大小虽然一样,但是密度不同,而最后的真实大小是按照英寸来画的,因为密度=像素/英寸,则 真实大小(英寸数)=像素/密度。那么这个问题怎么破,因为我们的程序一定是在相同大小的屏幕上有相同的大小,如果两个空间的大小一样,则是其英寸数相等,而英寸数又不能直接写在程序里,于是乎出现一个逆天的术语,dp。其实在2里我们看到过这个dp,那么什么是dp呢?

       dp在官网里叫Density-independent pixel (dp),即密度无关的像素,即可以摆脱密度的缠绕,就是前面我所提到的一种具有“去英寸化”功能的新的单位,我们先不提dp的具体计算(后面会说),我们就先假设这个dp就是一个全新的度量单位,让相等的dp在不同密度的屏幕里有相等的长度,比如1dp无论你是在设备1还是设备2,大小都是相等。这就是解决了“去英寸化”的问题。

4 dp的应用与图片问题

   通过3的描述,我们应该可以知道,在layout里任何的控件都采用dp就可以保证显示一致的问题了。这也是google所推荐的。

    但是对于图片这种外来户,我们可以规定它在layout中的大小,假如我们规定了图片的宽度1英寸(可以转为dp,后面会将),对于一张图片,其真实的宽度为15像素,在密度为3dpi的屏幕中,可以显示3个像素,这时需要丢掉12个像素,图片一定极为不清晰;在密度为15dpi的屏幕里可以显示15个像素,显示完全。这就有了分辨率的问题,在宽度都为1英寸的情况下,肯定是能够显示全部15个像素的图片清晰,怎么能让不同密度的屏幕显示的照片都比较清晰呢,我们可以对不同密度的屏幕选择不同的图片,即高密度选择高清图片。对于任何一张图片,我们都可以做三张,一张低分辨率,一张高分辨率,一张中间值,对于高密度的屏幕,比如密度为15,我们选择一张分辨率较高的图片(就是大的图片),如15英寸的,对于密度为3的,我们让它显示一张分辨率为3的,则保证了不会丢失信息,从而保证图片清晰。

    对于不同密度的屏幕,可以通过/res/drawable-hdpi等进行选择图片。这个官网也有。

5 dp的计算  

    其实我们没必要对dp进行计算,但是为了便于理解,我还是把dp的计算说一下, px = dp * (dpi / 160).这是官网的计算公式。对于一个密度为160dpi的屏幕而言,一个px就等于一个dp。。。。

   另外:android里字体的大小采用sp,具体的还没有研究,不过作用估计和dp差不多。

 
来自:http://blog.csdn.net/zhao123h/article/details/29564071