1. 程式人生 > >android螢幕適配問題分析及各種解決方案優缺點分析

android螢幕適配問題分析及各種解決方案優缺點分析

在這裡插入圖片描述

從事android開發已有5年之久,專案中遇到的螢幕適配的問題也有n次了,可是有一個很奇怪也很讓人頭疼的現象讓從事多年開發的我很不爽。什麼問題呢,就是“適配虐我千萬遍,我見適配如初見”,真是想說一句fuck,這次我終於堅決的征服掉了她,下面就來具體講解征服她的全過程,一定要有決心,耐著性子慢慢看。

  本著不重複造輪子的理念,對現有適配方案統統拿來細細研讀了一番,得出的結論是已基本可以解決適配問題,但是如果你去百度可以發現有不止一種解決方案,這些方案哪一個更好呢,聽我來慢慢分析。(客官莫急,要知道心急吃不到“熱豆腐”)。

參考

首先,為了節約用紙,涉及到的一些基礎知識就不在這裡贅述了,留下傳送門方便小白穿越:

android UI設計圖片和文字尺寸px對應dp、sp值換算
Android 螢幕適配:最全面的解決方案

下面是現有各種方案總結比較好的文章:

  1. px適配法:
    Android螢幕適配dp、px兩套解決辦法
  2. dp適配法:
    Android螢幕適配之dp分包法
    Android dp方式的螢幕適配-原理(後期補充完整講解)
  3. 百分比適配法:
    Android 螢幕適配方案
    Android 百分比佈局庫(percent-support-lib) 解析與擴充套件
  4. 單位轉換法:
    一行程式碼搞定安卓全螢幕適配

適配問題由來

為了方便閱讀本文,還是囉嗦補充幾個基礎要點,以免“仁者見仁”:

  1. dp/dip:密度無關畫素,1dp=1/160 inch 看公式就可以理解。
  2. dpi :畫素密度,即每英寸內畫素數

從上面dp的公式可以看出官方提供的dp單位只是畫素無關 但是和尺寸很有關,所以dp無法適配差別較大的尺寸螢幕,這也就是螢幕適配問題的由來。

各方案簡析

首先要普及一個概念叫“最小寬度限定符”,系統可以識別這些限定符來匹配相對應的螢幕尺寸所需要的資原始檔,最常用的例子就是mipmap-xdpi作為圖片資源的限定,那其實所有res的資源都有對應的限定符,比如layout佈局檔案有layout-large限定符來匹配大屏,values也有類似的限定符供app執行時選取。

方案一:px適配法原理
  以某一解析度(比如480*320)的 寬度 為基準,其他解析度按寬度等比例縮放(高度由於習慣滑動,所以採用寬度為基準),在values檔案的dimens檔案中定義x1=1px…x320=320px。如果UI設計師是在寬度為640px的螢幕上做的標註,那麼1px在xml中引用資源變數為x0.5,也就是要用小數來表示了,所以採用較大寬度的解析度作為基準比較合適,推薦使用1080作為基準。
  基準值選好後以此生成其他各解析度對應的資原始檔,理論上是生成的檔案越多適配誤差越小,但是受限於安裝包大小一般選取主流解析度適配。

方案二:dp適配法原理
  這種方案原理和px適配法是一樣的,只是“最小寬度限定符”的單位不同罷了。用dp作為限定符的好處是可以減少適配資原始檔的數量。這裡有一個容易誤解的點dp作為限定符來區分不同寬度的螢幕,在計算比例時容易理解為dp總值的比例,例如360dp和480dp的換算比例易誤解為480/360=1.5,其實不是這樣子的。比例的結果還是要將寬度換算為px的出。具體dp到px轉換可以參考上文傳送門的基礎篇,比較詳細。

方案三:百分比適配法原理
  這個方案也是和px適配法同樣的原理,百分比顧名思義只需要在px基礎上除以總寬度即可。而且現在也不需要再去手寫了,官方已經給出相容包提供百分比佈局:PercentRelativeLayout、PercentFrameLayout,線性佈局的百分比佈局沒有給出可在參考連結中鴻神的文章裡檢視到親手仿製的。

方案四:單位轉換法原理
  此種方案的原理比較簡單粗暴,系統進行長度計算的介面為TypedValue中的applyDimension函式,傳入單位與value將其計算為對應的px數值:

public static float applyDimension(int unit, float value,DisplayMetrics metrics){
      switch (unit) {
          case COMPLEX_UNIT_PX:
          return value;
          case COMPLEX_UNIT_DIP:
          return value * metrics.density;
          case COMPLEX_UNIT_SP:
          return value * metrics.scaledDensity;
          case COMPLEX_UNIT_PT:
          return value * metrics.xdpi * (1.0f/72);
          case COMPLEX_UNIT_IN:
          return value * metrics.xdpi;
          case COMPLEX_UNIT_MM:
          return value * metrics.xdpi * (1.0f/25.4f);
      }
	return 0;
}
  1. 可以看見換算方法非常簡單,而DisplayMetrics的所有屬性都是public的,不用反射就能修改;
  2. pt的原意是長度單位磅,根據當前螢幕與設計圖尺寸將metrics.xdpi進行修改就可以實現將pt這個單位重定義成我們所需要的相對長度單位,使修改之後計算出的1pt實際對應的px/螢幕寬度px=1px/設計圖寬度px。
  3. 而這個DisplayMetrics從哪來?從原始碼中可以看出一般為mContext.getResources().getDisplayMetrics(),這個mContext即為所在Activity;
  4. Activity中所拿到的DisplayMetrics與Application中拿到的DisplayMetrics雖然不是一個例項,但是所有數值都相同,在Application中進行更改也會影響到所有Activity中;
  5. Configuration的變化會導致DisplayMetrics的重新計算還原,需要handle;
  6. px,dp與sp都是平時常用的單位,而pt,in與mm幾乎沒有看見過,從這些不常見的單位下手正好可以不影響其他常用的單位。

各方案優缺點分析

方案一

  1. 由於解析度碎片化過於嚴重,想要高度適配市場機型需要很多很多的適配檔案,造成打包檔案過大。
  2. 新機春筍般發展,幾乎不可能覆蓋所有機型。

方案二

  1. 相較方案一適配資原始檔減少一些,但依然不少。
  2. 同樣不能覆蓋所有機型,但是對新機型的適配率高很多。

方案三

  1. 省去了這些資原始檔,增加了一個依賴包,不過記憶體佔用量肯定是少了很多。
  2. 可以覆蓋所有機型。
  3. 使用不太方便,尤其在巢狀比較多的佈局裡。因為UI給的圖標註全是px,每個細小的標準都要自己計算成百分比也是不小的工作量,而且UI有的時候不會把狀態列、標題欄、虛擬按鍵考慮進去,最後執行出來的效果可能和設計效果圖有一定差距。

方案四

  1. 不佔記憶體。
  2. 可以覆蓋所有機型。
  3. 修改系統單位pt,雖然這個單位很冷門,但是既然存在肯定還是有使用的地方,可能會造成一些無法預知的問題。

以上四種方案在佈局預覽時都需要使用和UI設計同樣的尺寸。

總結

綜合以上分析方案二相較方案一適配性更好優先選擇,方案三在簡單佈局上優勢較為明顯,方案四不穩定因素較多。

最後,感謝看到這裡的同學,有哪裡覺得不理解或者感覺不對的地方歡迎評論留言,會盡快回復。
在這裡插入圖片描述