本项目已经上传至码云,有兴趣的哥们可以参考。
码云:https://gitee.com/xuzhaoyu/ScreenPixelDemo
场景一:UI拿着一份1334 * 750(参照iPhone 8)的效果图时,各位Androider心里肯定千万个草泥马奔腾,这种分辨率的图能用?简直渣渣啊!放眼当下安卓阵营,1000-2000价位,遍地2K屏幕,遍地“全面屏”,1334*750这种“类720P”分辨率的苹果效果图,安卓百元机都不好意思用,还要我们做的与其一致?
场景二:在5.0寸的1920 * 1080设备上,一个Button的宽度为180dp,大概占屏幕宽度1/2。可是在6.8寸1920 * 1200的某设备上,该Button宽度居然只占了屏幕的1/4到1/3的样子,最终UI和产品验收产品的时候,BBBB,Androider心里同样千万个草泥马。
满满痛点啊!现今安卓阵营高分设备越来越多,屏幕适配刻不容缓,让我们自己动手,丰衣足食。如果您还不了解px,dp,dpi,请先移步补充px,dp,dpi的概念。
不知道诸位是否使用过鸿洋的AutoLayout,简直是安卓碎片化大背景下的屏幕适配的救星。不过可惜的是,AutoLayout已经停止更新很久,而且本身在兼容性上也存在一定问题,比如仅支持三大布局的如下属性:
1.layout_width
2.layout_height
3.layout_margin(left,top,right,bottom)
4.pading(left,top,right,bottom)
5.textSize
其次,Autolayout对部分含有虚拟按键的机型适配不佳。
再者,全面屏(18:9)机型也有很多,如果UI给的基准分辨率比例为16:9,在全面屏机型上会出现画面被拉高的问题。
那么我们该如何做屏幕适配呢?为了更好的兼容性,让我们回到屏幕适配的起点,看看基本的做法:在项目moudle/src/main/res/包下建立对应分辨率包,如values-1920 * 1080,values-1280 * 720等,并在每个包内创建合适的dimen,如下图所示:
当设备的分辨率为1920 * 1080时,就会读取values-1920 * 1080包下的dimen值,当设备分辨率为1280 * 720时,就会读取values-1280 * 720包下的dimen值,以此类推。
这种方式的兼容性毫无疑问是最佳的,而且也几乎不用考虑性能损失。如果采取这种方式进行适配,那么接下来的两个问题是:
1.我们到底有多少种分辨率?也就是要建立多少种values-xxxx*xxxx包?
2.然后又如何给每个包内生成dimen值?
一、主流设备的分辨率
为了保证兼容性,两行哥公司的App搜集了用户设备屏幕尺寸的信息,抓取到的分辨率如下(为期1年左右,近80款):
1440* 2427; 800 * 1217; 1600* 2434; 1024* 720; 1440* 2368; 1440* 2768; 1600* 2461; 1080* 1809; 1080* 2220; 1080* 2076; 1080* 2094; 1080* 1815; 1080* 1919; 1080* 1804; 1080* 2016; 1080* 2030; 720 * 1166; 1920* 1080; 1080* 2160; 720 * 1192; 1280* 720; 800 * 1232; 1080* 2034; 576 * 1024; 621 * 1104; 1080* 1797; 1080* 1803; 1080* 1825; 1080* 1810; 1200* 1920; 800 * 1216; 1200* 1848; 1080* 1848; 1200* 1852; 720 * 1200; 1080* 2040; 720 * 1216; 900 * 1600; 1200* 1830; 1080* 1821; 1152* 1920; 1600* 2560; 1440* 2434; 1600* 2452; 768 * 1184; 768 * 1280; 1536* 2048; 1440* 2792; 936 * 1664; 1080* 1788; 1080* 1794; 1080* 1830; 1080* 1800; 720 * 1208; 320 * 432; 320 * 480; 800 * 1280; 1440* 2416; 1200* 1824; 1080* 1806; 480 * 854; 1200* 1836; 1440* 2560; 1536* 2560; 1440* 2392; 1440* 2408; 1080* 1812; 600 * 976; 720 * 1242; 540 * 960; 1080* 1776; 240 * 320; 480 * 800; 480 * 640; 720 * 1184; 600 * 1024; 1080* 1920; 720 * 1280; 1440 * 2960; 720 * 1440。
那就以此为标准,我们根据上述分辨率建立values-xxxx * xxxx包。
二、生成dimen值
这里借用鸿洋的autolayout.jar工具(具体参见http://blog.csdn.net/lmj623565791/article/details/45460089)。
将图中标注的autolayout.jar拷贝至任意目录,在当前目录下打开命令窗口。例如,在windows环境下,在文件管理器中,按住Shift,右键,选择在此处打开命令窗口。在弹出的命令行窗口中,按照如下格式输入命令:
java -jar autolayout.jar defaultWidth defaultHeight targerWidth1,targetHeight1_targerWidth2,targetHeight2_targerWidth3,targetHeight3......
defaultWidth,defaultHeight就是基准分辨率,targetWidth和targetHeight就是目标分辨率,可以有多个目标分辨率。
例如:
UI的效果图基于1334 * 750(基准分辨率),上面有一个宽50px,高20px的控件,那么换算到目标分辨率(1920 * 1080 和 1280 * 720)上的宽高是多少呢?运行如下命令:
运行完毕你会发现在autolayout.jar所在的路径下生成了一个res文件夹,拷贝到项目中即可。
请先点进去看看res里面有什么,然后再继续阅读。
如果我们想把上述1334 * 750分辨率下效果图中宽50px,高20px的控件,适配到我们想要的分辨率中怎么办呢?写控件时的宽高为x50和x20就可以了(或者宽高为x50和y20,但是不建议,见下文),如下图:
稍微看一下,1920 * 1080分辨率下,x20 = 28.8px,x50 = 72px(<dimen name="x20">28.8px</dimen>,<dimen name="x50">72.0px</dimen>),即1920 * 1080 分辨率下宽28.8px,高72px与1334 * 750 分辨率下宽20px,高50px所占屏幕比例一致,做到了完美适配。
那么接下来就把两行哥生成dimen的代码附上,省的各位手敲麻烦:
java -jar autolayout.jar 750 1334 1600,2434_1600,2461_1600,2560_1600,2452_1536,2048_1536,2560_1440,2960_1440,2427_1440,2368_1440,2768_1440,2434_1440,2792_1440,2416_1440,2560_1440,2392_1440,2408_1200,1920_1200,1848_1200,1852_1200,1830_1200,1824_1200,1836_1152,1920_1080,1809_1080,2220_1080,2340_1080,2076_1080,2094_1080,1815_1080,1919_1080,1804_1080,2016_1080,2030_1080,2160_1080,2034_1080,1797_1080,1803_1080,1825_1080,1810_1080,1848_1080,2040_1080,1821_1080,1788_1080,1794_1080,1830_1080,1800_1080,1806_1080,1812_1080,1776_1080,1920_900,1600_800,1217_800,1232_800,1216_800,1280_768,1184_768,1280_720,1440_720,1166_720,1192_720,1200_720,1216_720,1208_720,1242_720,1184_720,1280_600,976_600,1024_576,1024_540,960_480,854_480,800_480,640_320,432_320,480_240,320
如果UI给的效果图是基于1920 * 1080的,那么把上述750(defaultWidth) 1334(defaultHeight)改成1080 1920即可,以此类推。然后参照效果图的标注,标注多少px,在项目中就使用dimen/x多少 或 dimen/y多少。
如果要保证控件宽高比例,建议不要使用y的值,因为现在18:9的屏幕也出来了,如果效果图是16:9,那么在18:9的屏幕中,单位y值已经变大,可能使控件被拉高而变形(不再是效果图中的宽高比),宽高都使用x值即可。如果控件不需要考虑宽高比例,只是需要保证宽高所占屏幕的百分比一致,那么宽使用x,高使用y。请各位读者自行思考琢磨。
三、其他优化
考虑一个问题,生成了这么多的values包,我们放入了app这个module。同时,我们项目也依赖了一些第三方的控件库module,在这些控件module里也有一些xml布局,如果我们想让它也适配屏幕,该如何做?难道我们在每个第三方控件库module的src/main/res/都拷贝这么多的values包吗?其实不用,可以参照Demo中的架构:
新建一个module,将这些values-xxxx * xxxx拷贝进去,然后让需要使用屏幕适配的module依赖这个module即可,如app module,还有一些第三方控件库module。那么就可以在你想用的地方尽情使用dimen值了。