Android分辨率适配

Android的分辨率适配问题一直是Android所让人诟病的主要问题,这里参考了官方的开发文档和实际开发中的一些处理分辨率的技巧来和大家交流一下。

官方的关于分辨率适配的文档“SupportingMultiple Screens”

Overview of Screens Support

  • Screen size:屏幕尺寸
  • Screen density:屏幕密度
  • Orientation:方向
  • Resolution:分辨率
  • Density-independent pixel (dp or dip):与像素类似的一个概念,是组成画面的最小颗粒度的单位,相当于160dpi屏幕上的一个物理像素点

Range of screens supported

Android从1.6(API Level 4)开始支持多分辨率适配,对屏幕尺寸和密度进行了划分:
* 屏幕尺寸:small,normal,large,xlarge
* 屏幕密度:ldpi(low),mdpi(medium),hdpi(high),xhdpi(extra high)

技术分享

这里尺寸和密度的基准是基于第一台Android机T-Mobile G1(HVGA Screen),所以为了减少产品的适配成本,只需要考虑在generailized size/density上的适配性。

在设计实际的Layout的时候,应该用的单位是dp,这样就可以避免因为屏幕的dpi不同所造成的影响,最典型的例子就是苹果的retina屏幕。

  • xlarge: at least 960dp x 720dp
  • large: at least 640dp x 480dp
  • normal: at least 470dp x 320dp
  • small: at least 426dp x 320dp

技术分享

px = dp * (dpi / 160)

例如一个240dpi的屏幕,1dp就相当于1.5个像素

px,dpi,dp,dip,sp

度量单位 解释
px(pixel像素) 像素单位
dpi(dots per inch像素密度) 每英寸的像素数,假设设备的分辨率是320 * 240,屏幕长2英寸宽1.5英寸,dpi=320/2=240/1.5=160
dp(density密度) 每平凡英寸的像素数Density=Resolution/Screen size
dip(Device-independent pixel,设备独立像素) 和dp相同,不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA、HVGA和QVGA 推荐使用这个,不依赖像素。dip和具体像素值的对应公式是dip值 =设备密度/160* pixel值,可以看出在dpi(像素密度)为160dpi的设备上1px=1dip
sp(ScaledPixels放大像素) 主要用于字体显示(best for textsize)。根据 google 的建议,TextView 的字号最好使用 sp 做单位,而且查看TextView的源码可知 Android 默认使用 sp 作为字号单位。
屏幕 密度 dpi 分辨率 匹配分组
QVGA density=0.75 densityDpi=120 QVGA(240 * 320) ldpi
HVGA density=1.0 densityDpi=160 HVGA(320 * 480) mdpi
VGA density=1.0 densityDpi=160 VGA(480 * 640) mdpi
WVGA density=1.5 densityDpi=240 WVGA(480 * 800) hdpi
WQVGA density=2.0 densityDpi=120 WQVGA(240*400) xhdpi

为什么在设计UI的时候要考虑dpi

这里举一个例子,在没有考虑dpi的情况下在界面上放一个32 * 32px大小的按钮,那么在同样是3.7寸,分辨率分别是480 * 320、600 * 480、800 * 600的手机的显示效果如下:

技术分享

由图可以看出,由于设备的dpi增大,1px在设备上对应的物理长度减少,最终的显示效果是组件看起来变小了。

用dpi来作为界面的尺寸标注单位

将控件的尺寸标注为32dip * 32dip,得到的显示效果:

技术分享

可以看出显示的效果好了很多。Android默认是使用density来匹配资源文件,而不是屏幕大小,同时图片分辨率和屏幕不匹配时,系统为需要大量的额外内存来对图像进行拉伸和缩放,这些额外的开销,会降低程序运行的效率。最关健是可能会引起内存溢出的异常,这是由android内存回收机制引起,对于大量图片使用的情况,发生的概率相当的高,目前没有有效办法解决。

获取density和dip

手机density和DIP可以使用以下方法获取,两种方法,一种是getWindowManager获取,一种是通过getResources的获取,两种结果是一样的,但因为某些原因,可能会有差异,有些手机厂商会修改API,有些厂商无良厂商会让低端屏故意显示高端的数据,如果你获取的屏幕数据不太准确,也不必太过在意:

void getDefaultDisplayScreenSize()
{
    DisplayMetrics dm = newDisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(dm);

    int screenWidthDip = dm.widthPixels;// 屏幕宽(dip,如:320dip)
    int screenHeightDip = dm.heightPixels;// 屏幕宽(dip,如:533dip)

    float density= dm.density;// 屏幕密度(像素比例:0.75/1.0/1.5/2.0)
    int densityDPI= dm.densityDpi;// 屏幕密度(每寸像素:120/160/240/320)

    float xdpi= dm.xdpi;
    float ydpi= dm.ydpi;

    w= dm.widthPixels;// 屏幕宽(px,如:480px)
    h= dm.heightPixels;// 屏幕高(px,如:800px)
}

void getDefaultDisplayScreenDensityDPI()
{
    DisplayMetricsdm = newDisplayMetrics();
    getResources().getDisplayMetrics();

    int screenWidthDip = dm.widthPixels;// 屏幕宽(dip,如:320dip)
    int screenHeightDip = dm.heightPixels;// 屏幕宽(dip,如:533dip)

    float density= dm.density;// 屏幕密度(像素比例:0.75/1.0/1.5/2.0)
    int densityDPI= dm.densityDpi;// 屏幕密度(每寸像素:120/160/240/320)

    float xdpi= dm.xdpi;
    float ydpi= dm.ydpi;
}

屏幕适配的流程

1、声明应用兼容的屏幕尺寸
在manifest文件中用来声明应用兼容的屏幕尺寸。这样可以让设备判断是否采用屏幕兼容性模式(Screen Compatibility Mode)来运行应用。

2、为不同的屏幕尺寸提供不同的Layout布局
对面的布局文件分别放在layout-small,layout-normal,layout-large,layout-xlarge文件夹下。

3、为不同的dpi提供不同的图片资源
如果是用dip来标记组件的大小,在绘制图片的时候,会将以像素尺寸度量大小的图片资源做缩放操作来最终适应屏幕中组件的大小,很容易产生显示模糊、圆角变形等问题,所以会针对不同dpi准备不同的图片资源。如果为不同dpi设备准备了不同的图片资源,android参考文档中建议以3:4:6:8的比例来依次做ldpi,mdpi,hdpi和xhdpi上的资源,android官方有关参考文档“IconDesign Guidelines”

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。