為什麼要螢幕適配
Android開發過程中我們常用的尺寸單位有px、dp,還有一種sp一般是用於字型的大小。但是由於px是畫素單位,比如我們通常說的手機分辨例如1920*1080都是px的單位。現在Android螢幕解析度碎片化720x1280、1080x1920、2280x1080,這就造成例如187px會在各個解析度的機型上都是顯示一樣大小的,那肯定不是我們想要的效果,所以用px單位我們是難以達到適配效果的,那麼為什麼用dp可以呢?
使用px單位從左到右依次為 480 * 800、1080 * 1920、1440 * 2560
使用dp單位從左到右依次為 480 * 800、1080 * 1920、1440 * 2560
螢幕總寬度依次為 320dp、415dp、411dp
那麼什麼是dp?
dp指的是裝置獨立畫素,以dp為尺寸單位的控制元件,在不同解析度和尺寸的手機上代表了不同的真實畫素,比如在解析度較低的手機中,可能1dp=1px,而在解析度較高的手機中,可能1dp=2px,這樣的話,一個187dp高度的控制元件,在不同的手機中就能表現出差不多的大小了。
dp如何計算成px
android中的dp在渲染前會將dp轉為px,計算公式:
-
px = density * dp;
-
density = dpi / 160;
-
px = dp * (dpi / 160);
而dpi是根據螢幕真實的解析度和尺寸來計算的,每個裝置都可能不一樣的。
由於density不是固定不變的,所以每個解析度不同的裝置他們的density都肯定不相等,這樣就會造成每個裝置的寬/高對應的總dp都是不同的,假設480 * 800解析度的density是1.5,1080 * 1920解析度的density是2.6,1440 * 2560解析度的density是3.5。那麼它們對應的寬度總dp = (寬度px) / density,分別為320dp、415dp、411dp。可以看出單位為dp的時候三個裝置之間的差距就不是很大了,但是這樣肯定還是不能滿足我們對螢幕適配的要求的。下面來看看Android常見的三種比較成熟的螢幕適配方案,並分析這幾種方案的優劣。
螢幕適配方案
1.1 寬高限定符適配
設定一個基準的解析度,也就是設計圖對應的解析度,其他解析度都根據這個基準解析度來計算,在不同的尺寸資料夾內部,根據該尺寸編寫對應的dimens檔案。
比如我們的設計圖 375 * 667為基準解析度
-
寬度為375,將任何解析度的寬度整分為375份,取值為x1-x375
-
高度為667,將任何解析度的高度整分為667份,取值為y1-y667
那麼對於1080*1920的解析度的dimens檔案來說,
-
x1=(1080/375)*1=2.88px
-
x2=(1080/375)*2=5.76px
-
y1=(1920/667)*1=2.87px
-
y2=(1920/667)*2=5.75px
當程式碼裡面引用高度為y_187,在APP執行時會根據當前裝置解析度去找對應xml檔案中對應的高度,我們就可以按照設計稿上的尺寸填寫相對應的dimens引用了,這樣基本解決了我們的適配問題,而且極大的提升了我們UI開發的效率。
驗證方案
簡單通過計算驗證下這種方案是否能達到適配的效果,例如設計圖上有一個寬187dp的View。
480 * 800
-
設計圖佔寬比: 187dp / 375dp = 0.498
-
實際在480 * 800佔寬比 = 187 * 1.28px / 480 = 0.498
1080 * 1920
-
設計圖佔寬比: 187dp / 375dp = 0.498
-
實際在1080 * 1920佔寬比 = 187 * 2.88px / 1080 = 0.498
-
計算高同理
但是這個方案有一個致命的缺陷,那就是需要精準命中才能適配,比如1920x1080的手機就一定要找到1920x1080的限定符,否則就只能用統一的預設的dimens檔案了。而使用預設的尺寸的話,UI就很可能變形,簡單說,就是容錯機制很差。
1.2 smallestWidth適配
smallestWidth適配,或者叫sw限定符適配。指的是Android會識別螢幕可用高度和寬度的最小尺寸的dp值(其實就是手機的寬度值),然後根據識別到的結果去資原始檔中尋找對應限定符的資料夾下的資原始檔。
這種機制和上文提到的寬高限定符適配原理上是一樣的,都是系統通過特定的規則來選擇對應的檔案。
可以把 smallestWidth 限定符螢幕適配方案 當成這種方案的升級版,smallestWidth 限定符螢幕適配方案 只是把 dimens.xml 檔案中的值從 px 換成了 dp,原理和使用方式都是沒變的
├── src/main
│ ├── res
│ ├── ├──values
│ ├── ├──values-sw320dp
│ ├── ├──values-sw360dp
│ ├── ├──values-sw400dp
│ ├── ├──values-sw411dp
│ ├── ├──values-sw480dp
│ ├── ├──...
│ ├── ├──values-sw600dp
│ ├── ├──values-sw640dp
複製程式碼
驗證方案
1920 * 1080解析度的手機,dpi為420,我們同樣設定一個View為187dp寬
- density = (dpi = 420) / 160 = 2.6
- 螢幕總寬度dp = 1080 / density = 415
- 找到資料夾values-sw410dp下的187dp = 204.45dp
- 通過公式px = density * dp,計算出px = 531.57
- 算出佔螢幕寬度的比例,56.86 / 1080 = 0.492
1440 * 2560解析度的手機,dpi為560,我們同樣設定一個View為187dp寬
- density = (dpi = 420) / 160 = 3.5
- 螢幕總寬度dp = 1440 / density = 411
- 找到資料夾values-sw410dp下的187dp = 204.45dp
- 通過公式px = density * dp,計算出px = 715.57
- 算出佔螢幕寬度的比例,715.57 / 1440 = 0.496
因為識別的資料夾是values-sw410dp的資料夾,但是螢幕寬度為415dp和411dp,所以最後計算出的佔比會有一點點誤差,基本可以忽略不計,可以達到相對比較準確的適配效果
優點
- 非常穩定,極低概率出現意外
- 不會有任何效能的損耗
- 適配範圍可自由控制,不會影響其他三方庫
- 在外掛的配合下,學習成本低
缺點
- 侵入性高,在所有地方都需要引用。
- 還是沒有辦法覆蓋所有的機型解析度,部分機型可能適配效果還是不佳
- 不能以高度為基準進行適配
- 生成很多檔案,增大APP體積1~2M
1.3 今日頭條適配方案
今日頭條螢幕適配方案的核心原理在於,根據以下公式算出 density
預設px = density * dp,也就是螢幕總寬度dp = 螢幕寬度px / density,這個時候我們假設所有裝置上的螢幕總寬度dp會等於我們設計圖375dp,那麼可以得出一個公式:
density = 螢幕寬度px / 設計圖寬度(375dp)
然後我們通過系統api,將density賦值給系統,拋棄掉系統預設計算density的計算公式。
這樣可以很巧妙的實現螢幕適配,而且侵入性極低,甚至可以忽略不計。
驗證方案
1920 * 1080解析度的手機,我們同樣設定一個View為187dp寬,設計圖寬度為375dp
- density = (螢幕寬度px = 1080) / 375 = 2.88
- View寬度 = density * 187dp = 538.56
- 算出佔螢幕寬度的比例,57.6 / 1080 = 0.498
1440 * 2560解析度的手機,我們同樣設定一個View為187dp寬,設計圖寬度為375dp
- density = (螢幕寬度px = 1440) / 375 =3.84
- View寬度 = density * 187dp = 718.08
- 算出佔螢幕寬度的比例,718.08 / 1440 = 0.498
可以看出,這種方案是完全沒有誤差的,而且侵入性極低,只需要修改系統的density。雖然修改系統的density屬性會產生一小部分影響,但是基本都是很好解決的。
優點
- 使用成本非常低,操作非常簡單
- 侵入性非常低
- 可適配三方庫的控制元件和系統的控制元件
缺點
- 會全域性影響APP的控制元件大小,例如一些第三方庫控制元件,他們設計的時候可能設計圖尺寸並不是像我們一樣是375dp,這樣就會導致控制元件大小變形等一些問題。
參考文章
騷年你的螢幕適配方式該升級了!-SmallestWidth 限定符適配方案
廣而告之
本文釋出於薄荷前端週刊,歡迎Watch & Star ★,轉載請註明出處。