记一次Android UI适配填坑经过

记一次Android UI适配填坑经过

概述

Android的多屏幕适配算是一个老生常谈的话题,也是一个Android应用开发工程师的必备技能。Android设备五花八门,屏幕小到手表,大到几十上百英寸的TV,相同分辨率,不同屏幕尺寸,相同屏幕尺寸,不同分辨率,还有各大厂商的不同系统固件…一个app,要做这么多适配工作,真是太难了。
言归正传,最近加入了一个没有自带屏幕的android设备项目组,这个设备可以通过HDMI接口投屏到TV,投影仪,显示器等显示设备。接上显示器后,开机启动,系统会选择一个最优的屏幕分辨率,就是一个设备可以有多种显示分辨率,它的dpi是240,属于hdpi。入坑的时候,项目已经准备量产,等到卖出了一两百台的时候,陆续收到销售同事反应我们的设备在康佳,TCL,创维等的很多老电视机上显示不全。这锅,就如同想象般那样,来到了我的头上。由于之前没有做过TV相关的项目,对项目里面的适配的疑问被同事一再肯定,而且公司里面十几二十个TV都没有显示问题后就不敢再出声了(不同dimens.xml分别在values-mdpi,values-hdpi,values-xhdpi,values-xxhdpi,吓得我都不敢出声)

使用smallest width适配方案

不了解smallest width 适配的可以点接连接了解下。
和硬件厂商的同事沟通过后,知道设备会在启动的时候选择最佳的分辨率(之前同事一直强调只输出1920*1080),输出的dpi为240,就是hdpi。我们的UI设计稿尺寸是1920x1080,hdpi,1dp=1.5px,设计稿的最小宽度是720dp,那么可以以这个为基准,等比生成不同的dimen.xml,然后使用生成的dimens来适配即可。但是,项目功能已完成,几十上百个页面,不可能一个个的去手动修改…

项目适配的现状

和同事沟通过后知道,values-mdpi中的dimens.xml是按照设计稿来填,项目里大部分布局文件使用了dimens.xml里定义的尺寸,摘取部分内容如下:

    <dimen name="rm_list_view_width">668dp</dimen>
    <dimen name="rm_list_view_join_width">692dp</dimen>
    <dimen name="rm_list_title_top">90dp</dimen>
    <dimen name="desktop_title_width">312px</dimen>
    <dimen name="desktop_title_height">28px</dimen>
    ......

发现居然还有个别dimen是px为单位,不过如果是根据设计稿来写的,那么也是可以转化为正确的,后来发现是可以转化的,虚惊一场。
前面说到,布局文件中用dimens.xml中定义的只是大部分,也有很很多是直接写死在布局文件中,真是一口鲜血马上就喷出来了。不过问题也不算大,花半个小时写一个java命令行工具,直接把布局文件中写死的部分dimens替换为smallest width中生成的dimens。
最要命的是代码中写死尺寸,到这里一口老痰再也忍不住了…

最终的解决方案

1.根据设计稿生成不同的dimens.xml

smallest width适配的原理就是根据设计稿的尺寸,如设计稿的最小宽度是360dp(如1920x1080,xxxhdpi),按照比例生成不同的宽度的dimens.xml,然后在布局文件中使用这些定义的dimens,达到一套方案适配尽可能适配所有的屏幕。所以第一步是生成dimens.xml。这个工作已经有人做了,可以参考这个项目ladingwu/dimens_sw。根据项目实际情况,我们的设计稿是1920x1080,hdpi,那么1080/1.5=720dp,所以values-sw720dp就是基准。

2.把项目中已使用的dimens按比例生成多份,对应各个sw

如前文所述,项目中已经定义了dimens.xml命名是五花八门的,不可能对应smallest width方案所生成的名称,大概有200多个,一个个去换是不合适的了,工作量太大了。只能牺牲一下apk的体积(我们对apk体积要求不大),把这些定义好的也生成对应的values-swdp。
这个实现起来很简单,遍历前面生成的values-swdp目录,取出dimens.xml文件,利用Java的XML接口Document,使用DOM的方式,全部读出来,然后根据比例替换里面的dp,sp,px值即可。有一点比较恶心的是,项目里面使用的并不是设计稿中的720dp,一开始使用720dp作为基准,发现很多尺寸变大了,一脸懵逼,后来把UI设计稿拿出来对比了一下,才知道他们是按照1080dp的尺寸来写的,估计是直接把设计稿的标注直接当成dp值写进去了,后来换1080dp为基准,瞬间显示不全的问题解决了一半以上。

3.替换布局文件中直接使用的dp,px,sp

接下来就是直接写死在布局文件中的dp,px,sp值了。有了前面的经验,sw=720,hdpi(写死的dp值倒是按照hdpi来算的),只要遍历布局文件,通过正则表达式,匹配到xyzdp,xyzpx,xyzsp这种的直接使用smallest中对应数字的name项即可,如:

android:width="100dp" -> android:width="@dimen/dp100"

4.黎明前的黑暗

能用代码解决的问题,都已经用代码解决了,但是,还剩下一些写死在代码里的dp,sp和px,只能手动一个一个页面的去看,对比UI设计稿,发现问题就看对应的代码。最痛苦的莫过于这部分的工作,前面三部分加起来就两个小时,后面几十个页面,还有Dialog,PopupWindow这些只能直接去看代码…整整搞了一天,总体上基本过得去了,很多细节肯定还要和UI设计师讨论。

总结

开发的时候总会遇到各种问题,UI适配这种事情,说句心里话是不应该出现这么严重问题的。不过借着这个问题,把smallest width适配用来解决现有项目中的适配问题,发现smallest width适配方案确实是一个满意的方案。有一点需要注意,smallest width并不是万能适配,它并不能代替google UI适配中wrap_content,match_parent等规则,二者应该相辅相成,才能尽可能高地还原UI设计稿的效果。
说到UI设计稿的效果,一般来说,UI设计师只给一套设计稿,要适配所有屏幕,很多时候不能只看标注,或者说,看标注的时候应该将拓扑关系考虑进去。举个例子,一个ImageView,标注距离左边xdp,距离右边ydp,但是右边的View明显是居中,那么此时应该忽略左边的距离标注,只需要考虑右边的View居中,ImageView在右边的View的左边,距离ydp。如果写死左右距离,忽略了居中这个事实的话,那么在和设计稿不一致的屏幕时,显示效果就和UI设计稿的不一样了,或者说偏差就大了。

原创文章 25 获赞 12 访问量 1万+

猜你喜欢

转载自blog.csdn.net/half_bottle/article/details/103336546