前言:以前很火的屏幕適配方案不知道你們都去嘗試過寫進項目中沒,應該有一部分人在隔岸觀火,大概的緣由就是目前並無遇到能把項目重構的適配問題,另外一方面就是有的適配方案尚未很成熟的應用,都不想拿本身的項目去測試。就拿那些github開源庫上面的適配方案來講,沒有幾我的去上面提issues。就在最近我去試了一下今日頭條的適配方案,而後。。。哎~~接着往下看吧java
ppi(Pixels per inch) 指每英寸上的物理像素數數目,即 "像素密度「。通常再購買手機的時候都會在參數中看到該設備的ppi數值,ppi數值越大屏幕顯像效果越好。不過ppi是物理上的概念,是客觀存在的不會改變的值,跟開發中常見的dpi是徹底不一樣的。android
dpi(Dots Per Inch)指每英寸有多少個點,最初是用在印刷行業,用來描述每英寸有多少小黑點。dpi被用於Android開發中用來描述屏幕像素密度的單位,是手機出廠就寫在系統配置中的一個固定數值,通常是固定不變的,除非你root以後去系統文件中修改這個值,不過手機root有太多的風險,不推薦去root,開發中能夠用DisplayMetrics類去獲取dpi數值。git
ppi和dpi是沒有任何關係的。有些文檔中ppi 等於 dpi的言論都是瞎扯的,它們之間也沒有什麼換算關係,還有的文章說 dpi的取值取決於ppi處於哪一個dpi的範圍,而後取這個範圍最大的值,這一點是沒有任何的依據,至於dpi的賦值咱們也沒法得知手機廠商是根據什麼去肯定的。github
ppi的數值咱們能夠經過如下公式算出,通常的話手機參數裏面都能看到ppi的數值,該公式並不適用計算dpi。json
dpi不能用上面的公式求出,dpi能夠經過DisplayMetrics類的densityDpi屬性獲取當前手機的dpi數值,該類也能夠獲取到跟屏幕密度有關的其它屬性。通常獲取DisplayMetrics類有如下方法:app
方式1:
//content:Activity,Content,Application.
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
方式2:
//getSystemService能夠經過 Activity,Content,Application等獲取.
DisplayMetrics displayMetrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
複製代碼
爲何強調設計圖呢, 由於設計圖是UI設計師根據APP的類型以及使用場景精心設計的,同時設計稿直接決定app界面預期的顯示效果,決定了每一個控件預期的大小,而屏幕適配也是要解決在Android尺寸限制的範圍內,按照一套設計圖寫出的佈局要在大部分機型上面顯示效果都跟設計圖同樣。通常的設計師會給一套尺寸,好比1080 X 1920 即 360dp X 640dp 比例 9:16的,或者IOS和Android使用一套設計圖(通常都會讓Android用IOS的設計稿)。在沒有嚴格要求的話咱們只是使用了dp來寫佈局, 反正如今一直都是😭,漸漸的發現dp已經逃不過設計師的法眼了(好多機型顯示的效果都跟設計圖有較多的差別)。ide
接着看,國內Android手機的ppi數值是廠商定製的,跟手機的硬件相關,ppi數值越大顯像效果越好,但ppi只是描述了手機硬件方面的像素密度,並不用於開發中。每種通用的尺寸和密度都涵蓋一個實際屏幕尺寸和密度範圍。例如, 兩部正常屏幕尺寸的設備在手動測量時,實際屏幕尺寸和 高寬比可能略有不一樣。相似地,對於兩臺hdpi 屏幕密度的設備,其實際像素密度可能略有不一樣。 Android 將這些差別抽象歸納到應用,使您能夠提供爲通用尺寸和密度設計的 UI,讓系統按須要處理任何最終調整。(有可能Android手機系統出廠設置的dpi數值也會參考該取值範圍的)。佈局
ldpi(低)~120dpi
mdpi(中)~160dpi
hdpi(高)~240dpi
xhdpi(超高)~320dpi
xxhdpi(超超高)~480dpi
xxxhdpi(超超超高)~640dpi
小屏幕至少爲 426dp x 320dp
正常屏幕至少爲 470dp x 320dp
大屏幕至少爲 640dp x 480dp
超大屏幕至少爲 960dp x 720dp
複製代碼
爲了簡化屏幕適配,通常機型的dpi的取值會參考上面的範圍,可是總會有一些特殊的機型就是不採納官方的建議。如小米 MIX 2 分辨率 2160x1080 屏幕尺寸 爲6, ppi爲403 獲取到的dpi爲440,該分辨率下的手機dpi 大體爲480。爲何要強調dpi的數值呢?我想你們都知道咱們再佈局的尺寸方面都會選擇dp,由於dp是會隨着分辨率的不一樣而變化的,通常的關係以下:學習
dpi 120 : 1dp = 0.75px;
dpi 160 : 1dp = 1px;
dpi 240 : 1dp = 1.5px;
dpi 320 : 1dp = 2px;
dpi 480 : 1dp = 3px;
dpi 640 : 1dp = 4px;
計算公式:
px = density * dp;
dp = px / density;
density = dpi / 160;
複製代碼
根據上面的公式能夠看到dpi影響了dp轉px的數值,因此能夠說dp適配也就是dpi的適配,對於360dp X 640dp的設計稿來講,對應的分辨率爲1080 X 1920和1440 X 2560,使用的數值爲 1dp = 3px。正常的機型咱們使用dp的話基本能夠完成適配,可是當碰到分辨率同樣dpi不一樣的手機,好比dpi = 440 1dp = 2.75px 或者 dpi = 420 1dp = 2.625px 的機型的時候,那就懵逼了,如一個Button的寬度爲100dp,再dpi = 480的機型中顯示的寬度效果爲300px,再dpi = 440顯示的效果寬度爲275px,這樣咱們的佈局就會跟預期的不太同樣,這是dp沒法適配的。測試
另外如今主流的是大屏手機,長度方向的像素點通常大於1920px,大體在2040px~2880px之間,可是寬度基本保持再1080px,配置好的手機是1440px,市場90%以上主流手機寬度都是1080px的。如:
華爲:
nova 2s ,Mate 10 Pro 等等分辨率是2160X1080 dpi = 480 ;
nova 3 2340 x1080 dpi = 480;
小米:
MIX 2040x1080 dpi = 480, MIX2 2160x1080 dpi = 440 ,
Max 2160X1080 dpi = 480等等;
oppo:
R11s 2160x1080 dpi = 480, R15 2280x1080 dpi = 480,
等等...
複製代碼
手機dpi的大小決定了當前dp轉px的倍數關係,目前大部分機型的dpi都是480,也就是說設計圖上一個組件的margintop 爲100dp = 300px,那麼當運行在分辨率爲1080X2280的機型中該組件相對於設計圖的位置就會偏上,在分辨率爲1080x1920的機型中正常,這就會致使一個問題,在大屏手機中正好顯示完整的佈局會再小屏幕中就會出現控件被遮擋或者控件的高度比不一致,最明顯的就是開屏頁的logo位置。這也是dp沒法解決的適配問題。
我的而言,適配寬度用dp基本可以適配,畢竟那些特殊dpi的機型仍是少數,寫佈局注意點的話就不會出現太明顯的適配問題。適配高度就須要使用其餘的更有效的適配方式了。
寬高限定符適配和smallestWidth適配方案大體思想都是同樣,smallestWidth比寬高限定符更加的智能可靠。可是這兩種方案須要增長好多資源文件,想要適配什麼屏幕就要去配置該類型的資源文件,全局適配。這兩種適配方案再寬高適配上仍是頗有效果的。鴻神的AndroidAutoLayout已經中止維護了,我想你們都不會優先考慮這個方案了,這裏也不去討論。今日頭條適配方案我想你們都或多或少的瞭解過,該方案仍是比較精簡靈活的,能夠本身選擇以寬度適配仍是高度適配,下面是在高度緯度上面的測試數據:
設計圖:
360dp X 640dp 分辨率爲 1080 X 1920 這裏的屏幕高度包括狀態欄。
控件高度爲103dp 高度/屏幕高度 = 0.1609375.
模擬器 1:
分辨率爲 1080 x 2280 .實際是 1080 X 2136 .狀態欄高度Wie:72px.
控件高度爲103dp 高度/屏幕高度 = 0.1497093. 適配後:0.1609649.
模擬器 2:
分辨率爲 1080 x 1920 .實際是 1080 X 1776 .狀態欄高度Wie:72px.
控件高度爲103dp 高度/屏幕高度 = 0.18133803.適配後:0.16035.
模擬器3:
分辨率爲 480 * 800.狀態欄高度Wie:36px. 尺寸小於設計圖的.
控件高度爲103dp 高度/屏幕高度 = 0.19375. 適配後:0.16125.
小米4:
分辨率爲 1080 x 1920 .狀態欄高度Wie:60px.
控件高度爲103dp 高度/屏幕高度 = 0.16612904. 適配後:0.1609375.
小米MIX2:
分辨率爲 1080 x 2160 .狀態欄高度Wie:66px. 底部虛擬導航鍵高度爲:130px
控件高度爲103dp 高度/屏幕高度 = 0.13940887. 適配後:0.16108374.
OPPO R15:
分辨率 1080 x 2280. 尺寸是 6.28 . 狀態欄高度爲:84px.
控件高度爲103dp 高度/屏幕高度 = 0.13552631. 適配後:0.1609649.
華爲p20:
分辨率爲 1080 x 2240 .狀態欄高度Wie:85px.
控件高度爲103dp 高度/屏幕高度 = 0.13770053.適配後:0.16087344.
oppo R9s:
分辨率爲 1080 x 1920 .狀態欄高度Wie:54px.
控件高度爲103dp 高度/屏幕高度 = 0.1609375. 適配後:0.1609375.
複製代碼
用今日頭條的適配方案後再大屏手機中的高度比基本等於設計圖中的高度比,這樣在屏幕高度相差很大的真機環境中顯示效果會好不少。今日頭條適配方案更加的靈活,咱們再適配的時候雖然是全局的修改,可是咱們能夠指定特定的界面上不適配(也就是把設置恢復爲默認的設置),這樣即便是第三方的界面只要有代碼就能夠選擇適配適配。另外還能夠的自由的配置是以寬度爲基準仍是以高度爲基準點去適配,可是二者不能兼得。
那麼問題來了,再平常開發中只是適配寬度的話,碰見的需求很少,適配高度確實是碰見很多,而後我再適配高度的時候發現了問題。當咱們用今日頭條適配方案在高度上去適配大屏手機的話(好比分辨率爲1080X2160)那樣計算出來的dpi的數值確定會比原數值高好多。好比小米 MIX2 分辨率爲 1080 X 2160 高度適配以後再高度緯度的dpi數值爲523 那麼就是100dp = 317px,正常狀況的dpi爲440 100dp = 275px。高度適配以後對寬度方向影響很大的。對下表的數據分析能看出,目前流行機型的寬度定大部分都在1080,高度大於1920的機型居多,再大屏手機裏面咱們要首選適配高度的問題,先來看下一個簡單的適配問題。
需求: 開屏頁logo展現位置。
設計稿: 1080px X 1920px 360dp X 640dp。
logo: 大小100dp X 100dp 水平居中,marginTop100dp。topMargin / 屏幕高度:0.15635。
測試機型: 小米四(1080X1920) vivo x21(1080X2280)。
真機數據未適配前:
未適配前:
小米4:
10-12 10:28:25.146 12746-12746/cn.screen.adaptation E/WANG: getWidth300
10-12 10:28:25.146 12746-12746/cn.screen.adaptation E/WANG: getHeight300
10-12 10:28:25.146 12746-12746/cn.screen.adaptation E/WANG: topMargin / 屏幕高度0.15625
VIVO X21:
10-12 10:31:15.246 23724-23724/cn.screen.adaptation E/WANG: getWidth300
10-12 10:31:15.246 23724-23724/cn.screen.adaptation E/WANG: getHeight300
10-12 10:31:15.246 23724-23724/cn.screen.adaptation E/WANG: topMargin / 屏幕高度0.13157895
咱們能夠看到小米4手機的topMargin / 屏幕高度跟設計圖的一致。VIVO X21就相差很大了。這樣顯示出來的logo的位置就會跟設計圖設計的有很大的差距,這種差距是隨着手機豎直分辨率的增大而增大。
複製代碼
真機適配後:
高度適配後:
小米4:
10-12 10:28:25.146 12746-12746/cn.screen.adaptation E/WANG: getWidth300
10-12 10:28:25.146 12746-12746/cn.screen.adaptation E/WANG: getHeight300
10-12 10:28:25.146 12746-12746/cn.screen.adaptation E/WANG: topMargin / 屏幕高度0.15625
VIVO X21:
10-12 10:30:33.760 23502-23502/? E/WANG: getWidth356
10-12 10:30:33.760 23502-23502/? E/WANG: getHeight356
10-12 10:30:33.760 23502-23502/? E/WANG: topMargin / 屏幕高度0.15614036
咱們能夠明顯的看到logo的topMargin / 屏幕高度基本跟設計搞的一致,這樣就達到了logo在大多數機型上面顯示的效果跟設計稿的同樣。可是能夠發現logo的寬高都增長了56px,這也是由於適配高度的時候更改了dpi的數值,dpi的數值偏大就會形成全局的dp轉px的倍率變大,這樣咱們的logo的大小和該界面的其它的控件的大小都會有影響。
複製代碼
屏幕適配任重而道遠,咱們要針對設計稿,針對界面,針對控件去選擇咱們的適配方式,技術好並不表明好用,有的時候會反其道而行之。本人仍是很喜歡今日頭條適配方案的,用註解作起來逼格瞬間提高,想再那個界面適配就在那個界面適配,想取消適配就取消適配,也就一個註解的事。另外還有一點就是,適配方案推出那麼多時間也不短了,有幾個開發者實戰了呢?所謂實踐出真理今日頭條適配方案坑不少,咱們一塊兒慢慢踩~~歡迎你們提出文章裏面的錯誤,你們共同窗習!
注: 如下機型的dpi數值只有一部分獲得真機驗證,其他存在些許偏差望更正,體如今(寬/density)這個數值上。
機型 | 分辨率 | ppi | 尺寸 | 寬/density | 高/density |
---|---|---|---|---|---|
華爲暢享8 | 1440x720 | 269 | 5.99 | 360dp | 720dp |
華爲nova 2 | 1920x1080 | 440 | 5 | 360dp | 640dp |
華爲P9 | 1920x1080 | 424 | 5.2 | 360dp | 640dp |
華爲Mate 9 | 1920x1080 | 373 | 5.9 | 360dp | 640dp |
華爲P10 | 1920x1080 | 432 | 5.1 | 360dp | 640dp |
華爲Mate 10 Pro | 2160x1080 | 402 | 6 | 360dp | 720dp |
華爲nova 2s | 2160x1080 | 402 | 6 | 360dp | 720dp |
華爲暢享8 Plus | 2160x1080 | 407 | 5.93 | 360dp | 720dp |
華爲Mate 10 Pro | 2160x1080 | 402 | 6 | 360dp | 720dp |
華爲nova 2s | 2160x1080 | 402 | 6 | 360dp | 720dp |
華爲P20 Pro | 2240x1080 | 408 | 6.1 | 360dp | 746.7dp |
華爲P20 | 2244x1080 | 428 | 5.8 | 360dp | 748dp |
華爲nova 3e | 2280x1080 | 432 | 5.84 | 360dp | 760dp |
華爲nova 3i | 2340x1080 | 409 | 6.3 | 360dp | 780dp |
華爲nova 3 | 2340x1080 | 409 | 6.3 | 360dp | 780dp |
華爲Mate 10 | 2560x1440 | 498 | 5.9 | 360dp | 640dp |
華爲Mate 20 | 2560x1440 | 482 | 6.1 | 360dp | 640dp |
華爲Mate RS保時捷版 | 2880x1440 | 537 | 6 | 360dp | 720dp |
機型 | 分辨率 | ppi | 尺寸 | 寬/density | 高/density |
---|---|---|---|---|---|
小米紅米6 | 1440x720 | 295 | 5.45 | 360dp | 720dp |
小米Max 2 | 1920x1080 | 342 | 6.44 | 360dp | 640dp |
小米5X | 1920x1080 | 401 | 5.5 | 360dp | 640dp |
小米6 | 1920x1080 | 428 | 5.15 | 360dp | 640dp |
小米Max 2 | 1920x1080 | 342 | 6.44 | 360dp | 640dp |
小米MIX | 2040x1080 | 361 | 6.4 | 360dp | 680dp |
小米6X | 2160x1080 | 403 | 6.0 | 360dp | 720dp |
小米MIX 2s | 2160x1080 | 403 | 6.0 | 360dp | 720dp |
小米紅米Note 5 | 2160x1080 | 403 | 6.0 | 360dp | 720dp |
小米Max 3 | 2160x1080 | 350 | 6.9 | 360dp | 720dp |
小米MIX 2 | 2160x1080 | 403 | 6.0 | 392.7dp | 785.5dp |
小米8 SE | 2244x1080 | 424 | 5.88 | 360dp | 748dp |
小米8 | 2248x1080 | 402 | 6.21 | 360dp | 749.3dp |
小米8透明探索版 | 2248x1080 | 402 | 6.21 | 360dp | 749.3dp |
小米紅米6 Pro | 2280x1080 | 432 | 5.84 | 360dp | 760dp |
機型 | 分辨率 | ppi | 尺寸 | 寬/density | 高/density |
---|---|---|---|---|---|
OPPO A57 | 1280x720 | 282 | 5.2 | 360dp | 640dp |
OPPO A83 | 1440x720 | 282 | 5.7 | 360dp | 720dp |
OPPO A5 | 1520x720 | 271 | 6.2 | 360dp | 760dp |
OPPO R9S | 1920X1080 | 401 | 5.5 | 360dp | 640dp |
OPPO R11 | 1920x1080 | 401 | 5.5 | 360dp | 640dp |
OPPO R11 Plus | 1920x1080 | 367 | 6 | 360dp | 640dp |
OPPO R11s | 2160x1080 | 401 | 6.0 | 360dp | 720dp |
OPPO R11s Plus | 2160x1080 | 376 | 6.43 | 360dp | 720dp |
OPPO R15 | 2280x1080 | 402 | 6.28 | 360dp | 760dp |
OPPO A3 | 2280x1080 | 405 | 6.2 | 360dp | 760dp |
OPPO R17 | 2340x1080 | 402 | 6.4 | 360dp | 780dp |
OPPO Find X | 2340x1080 | 401 | 6.42 | 360dp | 780dp |
OPPO R17 Pro | 2340x1080 | 402 | 6.4 | 360dp | 780dp |
機型 | 分辨率 | ppi | 尺寸 | 寬/density | 高/density |
---|---|---|---|---|---|
vivo Y71 | 1440x720 | 269 | 6.0 | 360dp | 720dp |
vivo Y83 | 1520x720 | 270 | 6.22 | 360dp | 760dp |
vivo x7Plus | 1920x1080 | 386 | 5.7 | 360dp | 640dp |
vivo X20Plus | 2160x1080 | 376 | 6.43 | 360dp | 720dp |
vivo X20 | 2160x1080 | 401 | 6.0 | 360dp | 720dp |
vivo Y97 | 2280x1080 | 401 | 6.3 | 360dp | 760dp |
vivo X21屏幕指紋版 | 2280x1080 | 402 | 6.28 | 360dp | 760dp |
vivo X21 | 2280x1080 | 402 | 6.28 | 360dp | 760dp |
vivo Z1 | 2280x1080 | 403 | 6.26 | 360dp | 760dp |
vivo Y85 | 2280x1080 | 403 | 6.26 | 360dp | 760dp |
vivo NEX | 2316x1080 | 388 | 6.59 | 360dp | 772dp |
vivo X23 | 2340x1080 | 402 | 6.4 | 360dp | 780dp |
機型 | 分辨率 | ppi | 尺寸 | 寬/density | 高/density |
---|---|---|---|---|---|
魅族魅藍S6 | 1440x720 | 282 | 5.7 | 360dp | 720dp |
魅族15 | 1920x1080 | 403 | 5.46 | 360dp | 640dp |
魅族PRO 7 | 1920x1080 | 424 | 5.2 | 360dp | 640dp |
魅族魅藍Note 6 | 1920x1080 | 401 | 5.5 | 360dp | 640dp |
魅族16th | 2160x1080 | 402 | 6 | 360dp | 720dp |
魅族16th Plus | 2160x1080 | 372 | 6.5 | 360dp | 720dp |
魅族16 X | 2160x1080 | 402 | 6.0 | 360dp | 720dp |
魅族15 Plus | 2560x1440 | 494 | 5.95 | 360dp | 640dp |
魅族PRO 7 Plus | 2560x1440 | 515 | 5.7 | 360dp | 640dp |
機型 | 分辨率 | ppi | 尺寸 | 寬/density | 高/density |
---|---|---|---|---|---|
錘子科技Smartisan T2 | 1920x1080 | 445 | 4.95 | 360dp | 640dp |
錘子科技堅果Pro | 1920x1080 | 401 | 5.5 | 360dp | 640dp |
錘子科技堅果Pro 2S | 2160x1080 | 402 | 6.0 | 360dp | 720dp |
錘子科技堅果Pro 2 | 2160x1080 | 402 | 6.0 | 360dp | 720dp |
錘子科技堅果R1 | 2240x1080 | 403 | 6.17 | 360dp | 746.7dp |