1. 程式人生 > >Android dp方式的螢幕適配-原理(後期補充完整講解)

Android dp方式的螢幕適配-原理(後期補充完整講解)

Android dp方式的螢幕適配-原理

傳統所說的螢幕適配,其實是針對不同螢幕的UI尺寸適配,即在編寫頁面時使用了具體的dp、sp值後導致的其他問題。
我之前寫過一些相關的文章和工具外掛,也收到了很多網友的反饋。
今天特編寫此篇部落格,重新整理以前的思路,同時也融入我近期更深刻的理解和總結,完整解答各位網友的疑惑。

友情連結,感謝鴻神提供的思路。
張鴻洋的《Android 螢幕適配方案》:

和其他大神的相關部落格,自行搜尋

我的前幾篇文章:
Android螢幕適配dp、px兩套解決辦法

Android dp方式的螢幕適配工具使用(bat批處理方式)

Android dp方式的螢幕適配工具使用(Android Studio外掛方式)

Android dp方式的螢幕適配工具使用(一些疑惑和注意事項)

我們按照下面問題的綱要和對應解答,來一步步思考和理解我的解決思路。

1、背景1:google建議我們在編碼時使用計量單位為dp、sp、match_parent或wrap_content。

*單位dp和sp。
上述google給我們的建議,都知道。
順便露一句:1dp=(1/160*)(inch)=(2.54/160)(cm)。在任何裝置上都是定長,除非裝置引數被廠商修改。

[dp等於物理定長]
官網連結:

2、對於《多螢幕適配》,究竟是出了什麼疑難問題?(需要產品介入抉擇)


*在不同的寬度dp的手機上需要實現等比縮放。

如上圖。我們按照google的建議,編碼UI時,使用dp的方式硬編碼,那麼在不同寬度dp的手機上的視覺效果會有誤差,感覺佈局向某一側擠壓了。
當然,需要說明的是,控制元件的物理長度是不變的,因為我上面提到dp等於現實世界的物理長度。

而不同手機的寬度dp值可能是不一樣的,這就是問題所在。

如果產品需要上圖2中的效果,實現不同寬度dp的手機展現的UI整體佈局一致,怎麼辦?
這就是多螢幕適配UI的問題。
當然,產品樂意圖1的效果,有點整體偏差無所謂,那就不需要看下文了,over。

此時,我們明確一個需求,UI在不同的寬度dp的手機上需要實現等比縮放,達到UI整體效果一致。

3、背景2:google提供了資源目錄的限定符規則。


*基於google的sw<N>dp限定符規則,提供多套dimens.xml檔案。
即google允許在專案 res/ 目錄內支援的資源目錄建立帶有限定符規則的同名目錄。

如:drawable-hdpi,layout-land,strings-en.xml等。
官網連結:

本文需要提到的是sw<N>dp限定符。請詳細閱讀官網文件的此章節。

在我的案例中,此限定符作用在values目錄上,如:

values-sw384dp
values-sw410dp
values-sw480dp

手機系統在執行期間,根據手機實際的寬度dp值,去尋找指定寬度dp的values目錄,然後使用裡面的一套資源作用在UI上。比喻手機執行時的實際寬度dp值是410,那麼系統會使用values-sw410dp下面的資源作用在app上。

但需要注意一點。如果你的手機寬度dp值為410.69。或許你可以生成values-sw410.59dp這個目錄來做適配,我沒試過。個人建議你寫成values-sw410dp,而不是values-sw410.59dp或values-sw411dp。因為系統會向下尋找等於或小於410.59的值的values目錄,直到預設的values目錄為止。

手機寬度dp值計算方法之一:

DisplayMetrics dm = getResources().getDisplayMetrics();
//手機寬度dp值 = 手機實際寬度畫素px / 手機螢幕密度比
float widthDP = dm.widthPixels / dm.density;

sw的意思是smallestWidth,即手機的最小寬度dp值。
其實更確切的說,是指手機寬度和高度的dp值中最小者。
對於常規手機而言,肯定是寬度dp值較小。如果手機切換成橫屏了,那麼就是高度dp值較小。
但無論是橫屏還是豎屏狀態,最小者的dp值是不變的。即無論橫豎屏狀態,此手機都只會尋找對應寬度dp的values目錄下的相關檔案(dimens.xml)來處理UI尺寸問題,而避免了橫豎屏切換時UI變形問題。

比喻你的手機寬度是360dp,高度是640dp。那麼無論是橫屏還是豎屏時,程式執行時都會尋找values-sw360dp的目錄(如果有)來作用在UI上。而不會是豎屏使用values-sw360dp,橫屏時使用values-sw640dp了,自己實驗。
如果你不希望這個結果,那麼你可以選擇values-w<N>dp的目錄方式,具體參考上面官網文件說明,自己實驗。


此時,我們理解了google官方的原理。剩下的,我們需要定義dimen變數,並生成對應手機寬度dp的dimens.xml檔案來作用在UI上,實現UI等比縮放效果。

4、手機寬度360dp和dp_360的由來,基礎dimen變數鍵值對定義。


*螢幕寬度等分為360份,認為dp_360變量表示沾滿螢幕,等價於match_parent。

在眾多的主流尺寸手機中,如1920x1080、1280x720等,測試發現,他們的手機寬度dp值是360dp,覆蓋範圍達到90%,但是不包括現在流行的全面屏、劉海屏(沒測試)。設計師提供的標註圖一般也是720px或者1080px的,我們拿來轉換為對應的dp值時也是預設基於360的基準值,如果讓設計師幫忙轉換也是一樣的結果。
即無論是對傳統尺寸手機寬度的計算,或者是開發期間開發和設計的共同認知,都認為是360dp為手機螢幕寬度值。
為了迎合這個標準,便於計算,所以我也就以360作為適配方案的基準值,即360的由來。

根據上面的潛認識,我把螢幕寬度的dp值定為dp_360這個變數(注意是變數,不是360dp這個固定值),
即把任意手機的螢幕等分為360份,
然後在預設的values/dimens.xml檔案中定義了一套變數,變數名和變數值是1:1關係的。
如:

好處是:
a、就算只使用values/dimens.xml檔案,也可適配90%的傳統手機。
b、變數的定義直觀易懂,螢幕等分為360份,每一份為dp_1,沾滿螢幕寬度為dp_360。
c、便於轉換設計圖px為dp值。
d、避免硬編碼,便於統一管理。就算不使用我的適配方案。


5、結合values/dimens.xml檔案的dp_xxx變數鍵值對和sw<N>dp規則,生成其他dimens.xml檔案。


*等比縮放dimens.xml的鍵值對的值。

例如:我有一個寬度為360dp和720dp的手機,如何基於已適配的360dp,再來生成720dp的dimens.xmla檔案呢?
手機寬度dp值從360變化到了720,增加了2倍,那麼把手機寬度為360dp的dimens.xml檔案中的每一個dimen值乘以2,變數名(鍵值)不變,是不是就實現了原理?

比喻一個按鈕寬度layout_width="@dimen/dp_180",在360dp寬度的手機上實際值是180dp,剛好是手機寬度的一半;在720dp寬度的手機上實際值是360dp,還是手機寬度的一半。
等比縮放效果[所得即所見]。

總算知道原理了,好用。但是總不能我手寫dimen檔案、手動乘法計算值吧?
當然,我有工具啊。請關注文章開頭的連線~~~~~~~
1、bat執行jar包的批處理方式。
2、Android Studio外掛方式。

6、針對某未知寬度dp值的手機,如何適配或取消適配?


*根據手機的寬度dp值,生成對應的values目錄和dimens.xml檔案。

如果確定要適配某手機,必須得知道該手機的實際執行時寬度dp值。
然後Android開發這邊得到這個dp值,工具生成對應的values和dimens.xml檔案即可。
無需修改頁面或者java類的程式碼,但是需要重新發版了。

若如想對640dp寬度的手機UI取消適配,怎麼辦?
僅僅只需要刪除 values-sw640dp目錄和子檔案即可。
無需修改程式碼,但是需要重新發版了。

當然了,未覆蓋到的範圍肯定是沒有處理UI等比縮放適配的了。這點是硬傷。


7、如何根據設計提供的px標註圖,轉換為dimens.xml中的dimen變數?


*除以基準值360,壓縮到手機可視範圍內。

常規的,設計會給寬度為1080或720px的圖。
我們假定以寬度755px的圖為例。
已知,設計給的圖尺寸寬高為755px-1265px,其中一個按鈕的畫素px值寬高為100px-50px,
怎麼在基於360等份的手機上編寫按鈕的dp值呢?

高度先不說。
基於寬度,設計圖755px,要壓縮到dp_360的範圍內。壓縮比例=755/360=2.1(約)。
即設計圖內的所有內容,都要壓縮2.1倍,才能用上基於dp_360範圍的變數。

搜嘎

按鈕寬度壓縮2.1倍,等於100/2.1=dp_48(約)(變數,不是具體的dp值)
類推,按鈕高度,等於50/2.1=dp_24
上面計算的約等於,取整或四捨五入都可以,接近即可。

之所以建議設計給出的設計圖為360的倍數,如720或1080,那是因為除以360基準值,得到的壓縮比例為整數。那麼後續我們在設定控制元件的寬高時就不用四捨五入得到近似值了。


8、基於寬度適配,忽略高度。


*基於寬度360等份的適配,高度自行使用ScrollView。

上面說到,基於設計圖的寬度,壓縮到360等份範圍的手機螢幕內。
但是注意,設計圖上的內容都保留了寬高比不變,即內容不會變形。

那麼又有另外一個問題,由於保證了內容寬高比不變,是不是會有些手機的螢幕無法容納整張設計圖內容?
對。!!!!!你自己使用ScrollView滾動吧。我要是限制高度,那麼在有些異形手機上必然會出現控制元件的高度擠壓或拉伸。並且上例中,控制元件的高度計算就不能使用寬度的壓縮比例了。這樣就更復雜,或者適配出的效果會更噁心了。

總結:

*把螢幕寬度等分成360份,實現UI在不同大小的手機上等比縮放。

我使用的values目錄限定符規則是sw<N>dp,上述提到的手機寬度dp值都指最小寬度,即手機寬度、高度dp值中的較小者,與當前橫、豎屏狀態無關。

如果你使用的限定符規則為w<N>dp,則寬度僅僅指代當前橫、豎屏狀態中的"寬度"dp值。橫、豎屏切換時"寬度"dp值會變化,系統會使用對應變化的values目錄下的資源。

手機、平板、電視開發都可以使用這套適配方案,但是使用的UI設計圖只能是針對各自型別的。例如,做電視開發時,只能使用針對電視而給出的UI設計圖,而不能使用手機的UI設計圖。

針對寬度dp值做螢幕適配時,建議不要其他領域的寬度dp值,即針對平板而開發的app,可以適配平板可能出現的其他寬度dp值,但是就不要新增手機或電視可能出現的寬度dp值了。針對平板的app執行在電視或手機上,UI本身就不搭調,適配了寬度dp值又有何用?

有點:工具生成,無需修改程式碼。新增或移除方便。

缺點:是否是產品需要的效果?無法覆蓋全部機型。

感謝QQ網友Alpha的優秀建議


參考文件: