記一次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設計稿的不一樣了,或者說偏差就大了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章