2018-05-20

前言

一款Android 屏幕適配方案。

網上關於屏幕適配的文章已經鋪天蓋地了,爲什麼我還要講?因爲網上現在基本都是使用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值來等比縮放而已。

問題:

  1. 既然原理都一樣,都需要多套dimens.xml文件,爲什麼說dp適配就比px適配好呢?
    因爲px適配是根據屏幕分辨率的,Android設備分辨率一大堆,而且還要考慮虛擬鍵盤。而dp適配無論手機屏幕的像素多少,密度比值多少,80%的手機的最小寬度dp值(widthPixels / density)都爲360dp,這樣就大大減少了dimens.xml文件。

  2. px適配會根據設備的分辨率去找對應的dimens.xml文件(如下圖,運行在分辨率爲1920x1080的手機上,系統會自動找到對應的values-1920x1080文件),那dp適配呢?

    [圖片上傳失敗...(image-86fd53-1541728256699)]

dp適配也是一樣的,只不過dp適配是根據“最小寬度(Smallest-width)限定符”來找的,需要注意的是“最小寬度”是不區分方向的,即無論是寬度還是高度,哪一邊小就認爲哪一邊是“最小寬度”。所以如果當前設備最小寬度(以 dp 爲單位)爲400dp,那麼系統會自動找到對應的values-sw400dp文件夾下的dimens.xml文件,如圖

[圖片上傳失敗...(image-8967ad-1541728256699)]

獲取設備最小寬度代碼,

        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阿杜提供了自動生成工具。

工具使用步驟:

  1. 在Android Studio中安裝ScreenMatch插件,如圖:

[圖片上傳失敗...(image-fdee03-1541728256699)]

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

[圖片上傳失敗...(image-de366b-1541728256699)]

github地址:ScreenAdaptation

  1. 執行生成
    插件安裝好後,在項目的任意目錄或文件上右鍵,選擇ScreenMatch選項。如圖:

[圖片上傳失敗...(image-578b15-1541728256699)]

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

[圖片上傳失敗...(image-48dbb3-1541728256699)]

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

[圖片上傳失敗...(image-ff6d3c-1541728256699)]

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

[圖片上傳失敗...(image-e4114a-1541728256699)]

通過上面的步驟就已經生成了所有設備對應的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文件)。配置文件在我們執行完成上面的命令後,會在項目的目錄下自動生成,如下:

[圖片上傳失敗...(image-d7d77-1541728256699)]

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

[圖片上傳失敗...(image-92e18-1541728256699)]

其中base_dp=360代表widthDP基準值,一般都是360dp,不建議更改,除非你對屏幕適配原理有深刻的見解。

當然!這些步驟你可以全部都不用做。直接複製我github上的各個dimens.xml文件到你項目即可!這些都是我在真實項目中使用的。

2、根據設計圖標註,在佈局寫上對應的值。

在安卓中,系統密度爲160dpi的中密度手機屏幕爲基準屏幕,即320×480的手機屏幕。在這個屏幕中,1dp=1px。320x480分辨率對應的其他分辨率的比例如下:

[圖片上傳失敗...(image-3f8d15-1541728256699)]

圖片來源: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

參考資料:

作者:wildma
鏈接:https://www.jianshu.com/p/1302ad5a4b04
來源:簡書
這是轉載別人的東西。樓主親測。還是可以的。上面的鏈接就是作者本人的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章