Android的分辨率适配问题一直是Android所让人诟病的主要问题,这里参考了官方的开发文档和实际开发中的一些处理分辨率的技巧来和大家交流一下。
官方的关于分辨率适配的文档“SupportingMultiple Screens”
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屏幕。
px = dp * (dpi / 160)
例如一个240dpi的屏幕,1dp就相当于1.5个像素
度量单位 | 解释 |
---|---|
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 |
这里举一个例子,在没有考虑dpi的情况下在界面上放一个32 * 32px大小的按钮,那么在同样是3.7寸,分辨率分别是480 * 320、600 * 480、800 * 600的手机的显示效果如下:
由图可以看出,由于设备的dpi增大,1px在设备上对应的物理长度减少,最终的显示效果是组件看起来变小了。
用dpi来作为界面的尺寸标注单位
将控件的尺寸标注为32dip * 32dip,得到的显示效果:
可以看出显示的效果好了很多。Android默认是使用density来匹配资源文件,而不是屏幕大小,同时图片分辨率和屏幕不匹配时,系统为需要大量的额外内存来对图像进行拉伸和缩放,这些额外的开销,会降低程序运行的效率。最关健是可能会引起内存溢出的异常,这是由android内存回收机制引起,对于大量图片使用的情况,发生的概率相当的高,目前没有有效办法解决。
手机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”
原文地址:http://blog.csdn.net/john_cdy/article/details/45332527