要实现程序的多屏适配,需要完成两个任务,一个是使得UI在不同的dpi下显示效果一致,即屏幕像素密度无关;另一个是为不同的屏幕尺寸设计合适的UI布局。
屏幕像素密度无关
在android屏幕分类中我们提到过,android设备的屏幕有不同的dpi(dots per inch,即像素密度),对160dpi的屏幕,1英寸有160个像素点,而对于240dpi的屏幕,1英寸则有240个像素点,也就是说,dpi越高,同样大小的区域内包含越多像素点。这就会造成同样像素大小的控件,在不同dpi的屏幕上显示的大小会不一样,如下图所示:
上图是两个screen size相等的屏幕,左边屏幕的分辨率为470 x 320,属于mdpi,右边屏幕分辨率为940 x 320,属于xhdpi,绿色方块是一个像素大小为300 x 300的ui控件。因为dpi越高,每英寸所包含的像素数越多,像素点越小,所以对于同样的控件,在dpi高的屏幕上显示会比较小。
像素无关单位DP
针对上面的问题,android提供了一种像素无关的单位dp(又叫dip,Density-independent pixel)
dp与px的换算公式为:px = dp * (dpi / 160)
系统会根据屏幕的dpi,将dp单位转化成适当的px值,由公式可知,对于160dpi(mdpi)的屏幕,1dp = 1px,对于240dpi(hdpi)的屏幕,1dp = 1.5px。只要用dp为单位定义UI控件的大小和位置,就可以使UI在不同dpi的屏幕上实现一致的显示效果,从而实现屏幕像素密度无关。例如上面的例子,只要在layout布局文件中把控件的宽高都定义成300dp,那么系统将会根据屏幕的dpi将该控件转化成适当的像素大小,如在mdpi下为300 x 300像素,在xhdpi下为600 x 600像素,如下:
常见的屏幕dpi和大小关系如下:
这5中主要的屏幕密度满足2:3:4:6:8的比例关系。
可以看到,dp单位是与屏幕密度无关的,不管你的屏幕dpi是多少,只要再代码中以dp为单位定义UI控件,那么在不同的屏幕密度下,视觉大小就能确保一致。
android系统以两种方式来帮助应用程序实现屏幕密度无关
- 系统根据当前屏幕dpi将dp单位转换成适当的px值
- 系统根据当前屏幕dpi将drawable资源缩放成适当的大小
为不同的屏幕尺寸提供合适的布局
使用orientation修饰符
很多情况下,特别是pad,不同方向下使用的布局时不一样的,而方向的改变也会影响屏幕当前宽度和高度,因此在资源文件中经常会使用到orientation修饰符
常用的资源修饰符组合
在代码中将dp转换成px:
总结:
1. 使用dp,wrap_content,match_parent来定义UI控件,text大小用sp,不要使用px。
2. 在mdpi,hdpi,xhdpi,xxhdpi的drawable目录中放置对应大小的位图,系统会根据屏幕dpi加载相应目录的图片。
3. 为不同的屏幕大小定义相应的资源文件,使用screen size修饰符和orientation修饰符,如layout-sw600dp-port。