【適配】【轉】一種極低成本的Android屏幕適配方式

原文地址:https://mp.weixin.qq.com/s/d9QCoBP6kV9VSWvVldVVwA

在Android開發(fā)中,由于Android碎片化嚴重技潘,屏幕分辨率千奇百怪舟扎,而想要在各種分辨率的設備上顯示基本一致的效果分飞,適配成本越來越高。雖然Android官方提供了dp單位來適配睹限,但其在各種奇怪分辨率下表現(xiàn)卻不盡如人意譬猫,因此下面探索一種簡單且低侵入的適配方式。

image

傳統(tǒng)dp適配方式的缺點

android中的dp在渲染前會將dp轉為px羡疗,計算公式:

  • px = density * dp;

  • density = dpi / 160;

  • px = dp * (dpi / 160);

而dpi是根據(jù)屏幕真實的分辨率和尺寸來計算的染服,每個設備都可能不一樣的。

屏幕尺寸叨恨、分辨率柳刮、像素密度三者關系

通常情況下嫩挤,一部手機的分辨率是寬x高爽蝴,屏幕大小是以寸為單位,那么三者的關系是:

image

舉個例子:屏幕分辨率為:1920*1080澜建,屏幕尺寸為5吋的話送矩,那么dpi為440蚕甥。

image

這樣會存在什么問題呢?

假設我們UI設計圖是按屏幕寬度為360dp來設計的益愈,那么在上述設備上梢灭,屏幕寬度其實為1080/(440/160)=392.7dp夷家,也就是屏幕是比設計圖要寬的蒸其。這種情況下, 即使使用dp也是無法在不同設備上顯示為同樣效果的库快。 同時還存在部分設備屏幕寬度不足360dp摸袁,這時就會導致按360dp寬度來開發(fā)實際顯示不全的情況。

而且上述屏幕尺寸义屏、分辨率和像素密度的關系靠汁,很多設備并沒有按此規(guī)則來實現(xiàn), 因此dpi的值非常亂闽铐,沒有規(guī)律可循蝶怔,從而導致使用dp適配效果差強人意。

image

探索新的適配方式

梳理需求

首先來梳理下我們的需求兄墅,一般我們設計圖都是以固定的尺寸來設計的踢星。比如以分辨率1920px * 1080px來設計,以density為3來標注隙咸,也就是屏幕其實是640dp * 360dp沐悦。如果我們想在所有設備上顯示完全一致成洗,其實是不現(xiàn)實的,因為屏幕高寬比不是固定的藏否,16:9瓶殃、4:3甚至其他寬高比層出不窮,寬高比不同副签,顯示完全一致就不可能了遥椿。但是通常下,我們只需要以寬或高一個維度去適配淆储,比如我們Feed是上下滑動的修壕,只需要保證在所有設備中寬的維度上顯示一致即可,再比如一個不支持上下滑動的頁面遏考,那么需要保證在高這個維度上都顯示一致慈鸠,尤其不能存在某些設備上顯示不全的情況。同時考慮到現(xiàn)在基本都是以dp為單位去做的適配灌具,如果新的方案不支持dp青团,那么遷移成本也非常高。

因此咖楣,總結下大致需求如下:

  1. 支持以寬或者高一個維度去適配督笆,保持該維度上和設計圖一致;

  2. 支持dp和sp單位诱贿,控制遷移成本到最小娃肿。

找兼容突破口

從dp和px的轉換公式 :px = dp * density

可以看出,如果設計圖寬為360dp珠十,想要保證在所有設備計算得出的px值都正好是屏幕寬度的話料扰,我們只能修改 density 的值。

通過閱讀源碼焙蹭,我們可以得知晒杈,density 是 DisplayMetrics 中的成員變量,而 DisplayMetrics 實例通過 Resources#getDisplayMetrics 可以獲得孔厉,而Resouces通過Activity或者Application的Context獲得拯钻。

先來熟悉下 DisplayMetrics 中和適配相關的幾個變量:

  • DisplayMetrics#density 就是上述的density

  • DisplayMetrics#densityDpi 就是上述的dpi

  • DisplayMetrics#scaledDensity 字體的縮放因子,正常情況下和density相等撰豺,但是調(diào)節(jié)系統(tǒng)字體大小后會改變這個值

那么是不是所有的dp和px的轉換都是通過 DisplayMetrics 中相關的值來計算的呢粪般?

首先來看看布局文件中dp的轉換,最終都是調(diào)用 TypedValue#applyDimension(int unit, float value, DisplayMetrics metrics) 來進行轉換:

image

這里用到的DisplayMetrics正是從Resources中獲得的污桦。

再看看圖片的decode亩歹,BitmapFactory#decodeResourceStream方法:

image

可見也是通過 DisplayMetrics 中的值來計算的。

當然還有些其他dp轉換的場景,基本都是通過 DisplayMetrics 來計算的捆憎,這里不再詳述舅柜。因此,想要滿足上述需求躲惰,我們只需要修改 DisplayMetrics 中和 dp 轉換相關的變量即可致份。

最終方案

下面假設設計圖寬度是360dp,以寬維度來適配础拨。

那么適配后的 density = 設備真實寬(單位px) / 360氮块,接下來只需要把我們計算好的 density 在系統(tǒng)中修改下即可,代碼實現(xiàn)如下:

image

同時在 Activity#onCreate 方法中調(diào)用下诡宗。代碼比較簡單滔蝉,也沒有涉及到系統(tǒng)非公開api的調(diào)用,因此理論上不會影響app穩(wěn)定性塔沃。

于是修改后上線灰度測試了一版蝠引,穩(wěn)定性符合預期,沒有收到由此帶來的crash蛀柴,但是收到了很多字體過小的反饋:

image

原因是在上面的適配中螃概,我們忽略了DisplayMetrics#scaledDensity的特殊性,將DisplayMetrics#scaledDensity和DisplayMetrics#density設置為同樣的值鸽疾,從而某些用戶在系統(tǒng)中修改了字體大小失效了吊洼,但是我們還不能直接用原始的scaledDensity,直接用的話可能導致某些文字超過顯示區(qū)域制肮,因此我們可以通過計算之前scaledDensity和density的比獲得現(xiàn)在的scaledDensity冒窍,方式如下:

image

但是測試后發(fā)現(xiàn)另外一個問題,就是如果在系統(tǒng)設置中切換字體豺鼻,再返回應用综液,字體并沒有變化。于是還得監(jiān)聽下字體切換拘领,調(diào)用 Application#registerComponentCallbacks 注冊下 onConfigurationChanged 監(jiān)聽即可意乓。

因此最終方案如下:

image

當然以上代碼只是以設計圖寬360dp去適配的樱调,如果要以高維度適配约素,可以再擴展下代碼即可。

image

Showcase

適配前后和設計圖對比:

image

適配后各機型的顯示效果:

image

參考

https://developer.android.com/guide/practices/screens_support.html

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末笆凌,一起剝皮案震驚了整個濱河市圣猎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌乞而,老刑警劉巖送悔,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡欠啤,警方通過查閱死者的電腦和手機荚藻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來洁段,“玉大人应狱,你說我怎么就攤上這事§羲浚” “怎么了疾呻?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長写半。 經(jīng)常有香客問我岸蜗,道長,這世上最難降的妖魔是什么叠蝇? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任璃岳,我火速辦了婚禮,結果婚禮上悔捶,老公的妹妹穿的比我還像新娘矾睦。我一直安慰自己,他們只是感情好炎功,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布枚冗。 她就那樣靜靜地躺著,像睡著了一般蛇损。 火紅的嫁衣襯著肌膚如雪赁温。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天淤齐,我揣著相機與錄音股囊,去河邊找鬼。 笑死更啄,一個胖子當著我的面吹牛稚疹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播祭务,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼内狗,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了义锥?” 一聲冷哼從身側響起柳沙,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎拌倍,沒想到半個月后赂鲤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體噪径,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年数初,在試婚紗的時候發(fā)現(xiàn)自己被綠了找爱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡泡孩,死狀恐怖缴允,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情珍德,我是刑警寧澤练般,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站锈候,受9級特大地震影響薄料,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜泵琳,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一摄职、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧获列,春花似錦谷市、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至巩梢,卻和暖如春创泄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背括蝠。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工鞠抑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人忌警。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓搁拙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親法绵。 傳聞我的和親對象是個殘疾皇子箕速,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容