前言
網上關於屏幕適配的文章已經鋪天蓋地了,為什么我還要講?因為網上現在基本都是使用px適配,即每種屏幕分辨率的設備需要定義一套dimens.xml文件。再加上有些手機還有虛擬按鍵(例如華為),這樣就還需要每個有虛擬按鍵的設備加多一套dimens.xml文件,再加上平板那些你會發現dimens.xml文件所占的體積已經超過2M了!這絕對不是我們想要的。
我這里要講的是使用dp來進行適配(Google推薦的也是這種方式),使用這種方式項目中多套dimens.xml文件才占幾百K,而且根本不用考慮虛擬按鍵的問題。這種方案已經在自己多個項目中應用過了,經過幾十台手機測試過,基本不會出現適配有問題的情況。制作生成對應dimens.xml文件插件的作者(后面會講)android阿杜也說過他在待過的兩家大公司實踐過,所以請放心使用。
為什么要進行Android屏幕適配?
關於為什么要進行Android屏幕適配,什么是dp、dpi這些概念我就不去一一講解了,網上很多文章。這里我推薦幾篇講的比較好的:
px與dp適配的原理
-
px適配原理:
根據設備屏幕的分辨率各自寫一套dimens.xml文件,然后根據一個基准分辨率(例如720x1080),將寬度分成720份,取值為1px——720px,將高度分成1080份,取值為1px——1080px。生成各自dimens.xml文件對應的值。 -
dp適配原理:
dp適配原理與px適配一樣,區別就在於px適配是根據屏幕分辨率,即拿px值等比例縮放,而dp適配是拿dp值來等比縮放而已。
問題:
-
既然原理都一樣,都需要多套dimens.xml文件,為什么說dp適配就比px適配好呢?
因為px適配是根據屏幕分辨率的,Android設備分辨率一大堆,而且還要考慮虛擬鍵盤。而dp適配無論手機屏幕的像素多少,密度比值多少,80%的手機的最小寬度dp值(widthPixels / density)都為360dp,這樣就大大減少了dimens.xml文件。 -
px適配會根據設備的分辨率去找對應的dimens.xml文件(如下圖,運行在分辨率為1920x1080的手機上,系統會自動找到對應的values-1920x1080文件),那dp適配呢?
dp適配也是一樣的,只不過dp適配是根據“最小寬度(Smallest-width)限定符”來找的,需要注意的是“最小寬度”是不區分方向的,即無論是寬度還是高度,哪一邊小就認為哪一邊是“最小寬度”。所以如果當前設備最小寬度(以 dp 為單位)為400dp,那么系統會自動找到對應的values-sw400dp文件夾下的dimens.xml文件,如圖

獲取設備最小寬度代碼,
DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); int heightPixels = dm.heightPixels; int widthPixels = dm.widthPixels; float density = dm.density; float heightDP = heightPixels / density; float widthDP = widthPixels / density; float smallestWidthDP; if(widthDP < heightDP) { smallestWidthDP = widthDP; }else { smallestWidthDP = heightDP; }
使用步驟
1、以某一widthDP為基准,生成所有設備對應的dimens.xml文件
生成這些文件當然不會手動去寫,網上已經有大神android阿杜提供了自動生成工具。
工具使用步驟:
- 在Android Studio中安裝ScreenMatch插件,如圖:

- 在項目的默認values文件夾中需要一份dimens.xml文件
我在github源碼已經提供了一份,直接復制過來即可。

github地址:ScreenAdaptation
- 執行生成
插件安裝好后,在項目的任意目錄或文件上右鍵,選擇ScreenMatch選項。如圖:

然后選擇在哪個module下執行適配。
即基於哪個module下的res/values/dimens.xml文件作為基准dimens.xml文件,生成的其他尺寸dimens.xml文件放在哪個module下。

點擊確定就會執行生成命令,如下代表生成成功。

然后再看看res目錄下會自動生成一堆dimens.xml文件,如下:

通過上面的步驟就已經生成了所有設備對應的dimens.xml文件。
因為默認生成的是下列最小寬度dp的dimens.xml文件
384,392,400,410,411,480,533,592,600,640,662,720,768,800,811,820,960,961,1024,1280,1365,如果不需要或者需要增加某些dp值的dimens.xml文件,則需要修改配置文件,即screenMatch.properties文件(修改前先刪除之前生成的全部dimens.xml文件)。配置文件在我們執行完成上面的命令后,會在項目的目錄下自動生成,如下:

打開文件,修改下面的值即可。如下只需要適配384,392,400,410,411的值,不需要適配480,533,592,600,640,662,720,768,800,811,820,960,961,1024,1280,1365的值

其中base_dp=360代表widthDP基准值,一般都是360dp,不建議更改,除非你對屏幕適配原理有深刻的見解。
當然!這些步驟你可以全部都不用做。直接復制我github上的各個dimens.xml文件到你項目即可!這些都是我在真實項目中使用的。
2、根據設計圖標注,在布局寫上對應的值。
在安卓中,系統密度為160dpi的中密度手機屏幕為基准屏幕,即320×480的手機屏幕。在這個屏幕中,1dp=1px。320x480分辨率對應的其他分辨率的比例如下:

圖片來源:UI設計師不可不知的安卓屏幕知識
所以,如果UI給的是720x1280分辨率的圖, 那么dp = px / 2, 給的是1080x1920分辨率的圖,那么 dp = px / 3,即根據比例即可。
舉例:UI在720x1280上做的圖,其中一個按鈕的寬高分辨為:寬720px,高為100px,字體大小為30px,在布局中則這樣使用:
<Button android:layout_width="@dimen/dp_360" android:layout_height="@dimen/dp_50" android:textSize="@dimen/sp_15"/>
代碼中動態設置dp或sp:
如果需要在代碼中動態設置dp或sp,則需要通過getDimension()方法獲取對應資源文件下的dp或sp值再設置(具體參考github上的demo)。如下:
/*獲取sp值*/ float pxValue = getResources().getDimension(R.dimen.sp_15);//獲取對應資源文件下的sp值 int spValue = ConvertUtils.px2sp(this, pxValue);//將px值轉換成sp值 mTvShowParams.setTextSize(spValue);//設置文字大小 /*獲取dp值*/ float pxValue2 = getResources().getDimension(R.dimen.dp_360);//獲取對應資源文件下的dp值 int dpValue = ConvertUtils.px2dp(this, pxValue2);//將px值轉換成dp值
怎么適配其他module?
- 問題:在項目的其他module中怎么實現適配?難道也要多套dimens?
- 解決:並不需要多套dimens,只需要在values文件夾下有一套與app module一樣的dimens文件即可達到適配。因為經過編譯,所有module中的dimen數據都會統一歸類到主module(即app module)中的values/dimens.xml文件中了,然后系統又會根據你設置的值去找對應values-swxxxdp文件夾下的dimens.xml文件中的值。
- 驗證:在項目中建一個module,然后隨便取一個dimens.xml文件中的值進行打印,分別運行在不同widthDP的設備上(用模擬器即可)觀察打印的結果發現確實是這樣的。
最后非常感謝大神android阿杜提供的插件,具體的dp適配與插件原理可以去看看他寫的文章。
github地址:ScreenAdaptation
參考資料: