程序性能優化之屏幕適配(七)

阿里P7移動互聯網架構師進階視頻(每日更新中)免費學習請點擊:https://space.bilibili.com/474380680java

本篇文章將推薦一種很是好用的Android屏幕適配:android

更新:因爲該適配方案愈來愈多人使用,也有不少人遇到不太理解的問題。因此爲了你們更好的使用,我將文章不少內容更新了,老用戶能夠從新看下整篇文章。主要更新的內容是使用方法跟之前不一樣了,之前是不改變最小寬度基準值,根據 UI 圖來計算佈局中設置的值。如今改爲最小寬度基準值與設計圖一致,而後設計圖標註多少 dp 就寫多少 dp,很是方便。還整理了評論區比較多人問到的問題做統一回答。git

前言

網上關於屏幕適配的文章已經鋪天蓋地了,爲何我還要講?由於網上如今基本都是使用 屏幕分辨率限定符 進行適配,即每種屏幕分辨率的設備須要定義一套 dimens.xml 文件。因爲不一樣分辨率的設備太多了,並且有些設備還有虛擬按鍵(例如華爲手機),這樣就還須要每一個有虛擬按鍵的設備加多一套 dimens.xml 文件,再加上平板那些你會發現 dimens.xml 文件所佔的體積已經超過2M了!這絕對不是咱們想要的。github

我這裏要講的是使用 sw<N>dp限定符,即 smallestWidth(最小寬度) 限定符 來進行適配,使用這種方式只須要少許 dimens.xml 文件便可達到適配,並且根本不用考慮虛擬按鍵的問題。若是隻適配手機,dimens.xml 文件所佔的體積只有 100 多 KB,即便加上平板和 TV,也就500多KB,徹底能夠接收。這種方案已經在本身多個項目中應用過了,通過幾十臺手機測試過,基本不會出現適配有問題的狀況。製做生成對應 dimens.xml 文件插件(後面會講)的做者也說過他在待過的兩家大公司實踐過,因此請放心使用。架構

爲何要進行屏幕適配?

關於爲何要進行屏幕適配,什麼是 dp、dpi 這些概念我就不去一一講解了,網上不少文章。這裏我推薦幾篇講的比較好的:app

屏幕分辨率限定符與 smallestWidth 限定符適配原理

屏幕分辨率限定符適配原理工具

屏幕分辨率限定符適配須要在 res 文件夾下建立各類屏幕分辨率對應的 values-xxx 文件夾,以下圖:佈局

 
5382223-eec94bc1a2aa34dc.png
image

而後根據一個基準分辨率,例如基準分辨率爲 1280x720,將寬度分紅 720 份,取值爲 1px~720px,將高度分紅 1280 份,取值爲 1px~1280px,生成各類分辨率對應的 dimens.xml 文件。以下分別爲分辨率 1280x720 與 1920x1080 所對應的橫向dimens.xml 文件:學習

 
5382223-117263d0f3c62d79.png
image

假設設計圖上的一個控件的寬度爲 720px,那麼佈局中就寫 android:layout_width="@dimen/x720" ,當運行程序的時候,系統會根據設備的分辨率去尋找對應的 dimens.xml 文件。例如運行在分辨率爲 1280x720 的設備上,系統會自動找到對應的 values-1280x720 文件夾下的 lay_x.xml 文件,由上圖可知 x720 對應的值爲
720.px,可鋪滿該屏幕寬度。運行在分辨率爲 1920x1080 的設備上,系統會自動找到對應的 values-1920x1080 文件夾下的 lay_x.xml 文件,由上圖可知 x720 對應的值爲 1080.0px,可鋪滿該屏幕寬度。這樣就達到了屏幕適配的要求!測試

smallestWidth 限定符 適配原理

smallestWidth 限定符適配原理與屏幕分辨率限定符適配原理同樣,系統都是根據限定符去尋找對應的 dimens.xml 文件。例如程序運行在最小寬度爲 360dp 的設備上,系統會自動找到對應的 values-sw360dp 文件夾下的 dimens.xml 文件。區別就在於屏幕分辨率限定符適配是拿 px 值等比例縮放,而 smallestWidth 限定符適配是拿 dp 值來等比縮放而已。須要注意的是「最小寬度」是不區分方向的,即不管是寬度仍是高度,哪一邊小就認爲哪一邊是「最小寬度」。以下分別爲最小寬度爲 360dp 與最小寬度爲 640dp 所對應的 dimens.xml 文件:

 
5382223-f1e46356e8ceb6dc.png
image
  • 獲取設備最小寬度代碼爲:
DisplayMetrics dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        int heightPixels = ScreenUtils.getScreenHeight(this);
        int widthPixels = ScreenUtils.getScreenWidth(this);
        float density = dm.density;
        float heightDP = heightPixels / density;
        float widthDP = widthPixels / density;
        float smallestWidthDP;
        if(widthDP < heightDP) {
            smallestWidthDP = widthDP;
        }else {
            smallestWidthDP = heightDP;
        }

ScreenUtils——>ScreenUtils

爲何選擇 smallestWidth 限定符適配?

既然原理都同樣,都須要多套 dimens.xml 文件,那爲何要選擇 smallestWidth 限定符適配呢?

  1. 屏幕分辨率限定符適配是根據屏幕分辨率的,Android 設備分辨率一大堆,並且還要考慮虛擬鍵盤,這樣就須要大量的 dimens.xml 文件。由於不管手機屏幕的像素多少,密度多少,90% 的手機的最小寬度都爲 360dp,因此採用 smallestWidth 限定符適配只須要少許 dimens.xml 文件便可。
  2. 屏幕分辨率限定符適配採用的是 px 單位,而 smallestWidth 限定符適配採用的單位是 dp 和 sp,dp 和 sp 是google 推薦使用的計量單位。又因爲不少應用要求字體大小隨系統改變,因此字體單位使用 sp 也更靈活。
  3. 屏幕分辨率限定符適配須要設備分辨率與 values-xx 文件夾徹底匹配才能達到適配,而 smallestWidth 限定符適配尋找 dimens.xml 文件的原理是從大往小找,例如設備的最小寬度爲 360dp,就會先去找 values-360dp,發現沒有則會向下找 values-320dp,若是仍是沒有才找默認的 values 下的 demens.xml 文件,因此即便沒有徹底匹配也能達到不錯的適配效果。

使用步驟

一、以設計圖最小寬度(單位爲 dp)做爲基準值,生成全部設備對應的 dimens.xml 文件

這些文件固然不會手動去寫,網上已經有大神提供了自動生成這些文件的插件 ScreenMatch。可是這個插件仍是有點問題的:

  • 默認沒有適配最小寬度爲 320dp 的設備。其實本身測試仍是有不少設備最小寬度是 320dp 的,因此須要加上。
  • 最小寬度爲 392.7272 與 411.4285 的手機不能達到徹底適配。緣由是該插件的默認值都是取整的,即 392.7272 與 411.4285 在插件中寫的是 392 與 411。

基於以上問題,我在該插件的源碼上優化生成了新的插件 ScreenMatch,因爲插件庫已經有原做者的插件了,因此我就不重複造輪子上傳到插件庫了,你直接用本地安裝的方式安裝便可。

工具使用步驟:

  1. 在 Android Studio 中安裝 ScreenMatch 插件
    下載插件 ScreenMatch 到本地,點擊菜單欄上的 File -> Settings -> Plugins -> Install plugin from disk,而後選擇咱們剛剛下載的插件,最後點擊 「OK」,重啓 Andorid Studio 便可。以下圖所示:
 
5382223-251f7d372f5ff80d.png
image
  1. 在項目的默認 values 文件夾中須要一份 dimens.xml 文件
    我在 github 源碼已經提供了一份,直接複製過來便可。
 
5382223-26da3eb3f32fffbc.png
image
  1. 執行生成
    插件安裝好後,在項目的任意目錄或文件上右鍵,選擇 ScreenMatch 選項。以下圖:
 
5382223-6ad9ee0eb0238886.png
image

而後選擇在哪一個 module 下執行適配。即基於哪一個 module 下的 res/values/dimens.xml 文件做爲基準 dimens.xml 文件,生成的其餘尺寸 dimens.xml 文件放在哪一個 module 下。例如選擇 app,而後點擊 OK ,出現以下界面表示生成文件成功。以下圖:

 
5382223-06d064480c7bbd75.png
image

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

 
5382223-29986645ad1009fb.png
image

經過上面的步驟就已經生成了全部設備對應的 dimens.xml 文件。

  1. 根據設計圖填寫最小寬度基準值,並填寫須要適配的設備最小寬度 dp 值

步驟 3 是以插件默認的最小寬度基準值爲 360dp,適配的設備最小寬度爲
320,360,384,392.7272,400,410,411.4285,432,480,533,592,600,640,662,720,768,800,811,820,960,961,1024,1280,1365(包含了平板和 TV )生成的文件,但實際狀況要根據設計圖和需求設置。

例如設計圖的最小寬度爲 375dp,則須要更改最小寬度基準值爲 375dp。若是項目只須要適配手機的話,適配的設備最小寬度保留 320,360,384,392.7272,400,410,411.4285,432,480 便可,若發現手機還有其餘最小寬度自行加上便可,也麻煩把該最小寬度提供給我,咱們一塊兒來完善該份適配。

以上修改須要在配置文件裏修改,即 screenMatch.properties 文件,該配置文件是執行完上面第 3 步後自動生成在項目的跟目錄下的。以下圖:

 
5382223-d40fc5ec1ba49959.png
image

打開配置文件,修改下圖中 一、三、4 的值便可。(圖中單位均爲 dp)
1:最小寬度基準值,填寫設計圖的最小寬度值便可。
2:插件默認適配的最小寬度值,即默認狀況下會生成以下值的 dimens.xml 文件。
3:須要適配的最小寬度值(若是是小數,則保留4位小數。例如 392.727272...,則取 392.7272),即你想生成哪些 dimens.xml 文件。
4:忽略不須要適配的最小寬度值,即忽略掉插件默認生成的 dimens.xml 文件。

 
5382223-4a2b88dd2101c46e.png
image

配置文件修改完成後,從新執行第 3 步,生成新的 dimens.xml 文件。

固然!若是你的設計圖也是標準的 360dp,那麼上面的步驟你能夠忽略。直接複製我 github 上你須要的 dimens.xml 文件到你的項目便可,默認的 values 文件夾下也須要一份

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

設計圖標註多少 dp,佈局中就寫多少 dp ,很是方便!

  • 大多數 UI 設計師提供設計圖有以下幾種方式:
    上傳到藍湖:顯示多少 dp 就寫多少 dp。
    psd 源文件:用像素大廚查看,顯示多少 dp 就寫多少 dp(注意像素大廚須要選擇與設計圖對應的dpi 進行顯示)
    dp 單位的設計圖:標註多少 dp 就寫多少 dp。
    px 單位的設計圖:叫 UI 設計師標註爲 dp 單位或跟她要 psd 源文件,若是都不行,那本身算吧!

  • 舉例:例如設計圖上一個Button 的寬爲 360dp,高爲 50dp,字體大小爲 15 sp,在佈局中則這樣使用:

<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值

使用步驟總結

說了這麼多,其實只須要簡單的 2 步:

  1. 以設計圖最小寬度(單位爲 dp)做爲基準值,利用插件生成全部設備對應的 dimens.xml 文件
  2. 根據設計圖標註,標註多少 dp,佈局中就寫多少dp,格式爲@dimen/dp_XX。

怎麼適配其餘 module?

  • 問題:在項目的其餘 module 中怎麼實現適配?難道也要多套 dimens 文件?
  • 解決:並不須要多套 dimens 文件,只須要在 values 文件夾下有一套與 app module 同樣的 dimens 文件便可達到適配。由於通過編譯,全部 module 中的 dimen 數據都會統一歸類到主 module(即 app module)中的 values/dimens.xml 文件中了,而後系統又會根據你設置的值去找對應 values-swxxxdp 文件夾下的dimens.xml 文件中的值。
  • 驗證:將我 github 上的 demo 分別運行在不一樣 widthDP 的設備上(用模擬器便可),而後觀察顯示的效果會發現確實是這樣的。

常見問題彙總

爲何寬度適配了,高度有時候沒有徹底適配?

由於各類屏幕高寬比並非固定的,有16:九、4:3,還有全面屏的19.5:9等等,若是強行將寬高都適配那隻會致使佈局變形。

例如一個控件的寬高爲360dp和640dp,若是將它顯示在寬高爲360dp和640dp的設備上是正常鋪滿整個屏幕的,可是顯示在寬高爲360dp和780dp的設備上高度則不能鋪滿,若是你讓高度鋪滿,而寬度又保持不變,那就會出現變形的狀況。因此這也就是爲何目前市面上的屏幕適配方案只能以寬或高一個維度去適配,另外一個方向用滑動或權重的方式去適配的緣由。

那你爲何說高度也能適配呢?
這裏說的高度也能適配指的是在不一樣分辨率和密度的手機上能達到等比縮放的適配,其餘屏幕適配方案也是同樣的。

如何同時適配橫豎屏?

  • 方案一:(不推薦)
    計算出設備寬度和高度的dp值,而後生成對應的寬高 dimens.xml 文件。而後去掉全部 values-swXXXdp 目錄上的s,即改成 values-wXXXdp。這樣設備無論橫豎屏都能找到對應的 values-wXXXdp 目錄下的 dimens.xml 文件了。 雖然也能達到必定程度的適配,可是這樣會增長不少 dimens.xml 文件,並且使用豎屏的設計圖顯示出來的效果也不夠好。

  • 方案二:(推薦)
    由於橫屏時寬高變化太大,想要橫屏時也能徹底適配,那就只能讓設計師出一套橫屏的設計圖,而後單獨寫一套橫屏的佈局文件。

注意:smallestWidth 限定符適配的效果是讓不一樣分辨率和密度的設備上能達到以設計圖等比縮放的適配,若是設備與設計圖相差太大時並不能達到很好的適配效果,須要單獨出圖,其餘屏幕適配方案也是同樣的。

如何適配平板、TV?

同橫屏道理同樣,平板、TV 與手機的寬高差距太大,想要平板、TV 也能徹底適配,那就只能讓設計師出一套平板、TV 的設計圖,而後單獨寫一套平板、TV 的佈局文件。

注意:再說一遍,smallestWidth 限定符適配的效果是讓不一樣分辨率和密度的設備上能達到以設計圖等比縮放的適配,若是設備與設計圖相差太大時並不能達到很好的適配效果,須要單獨出圖,其餘屏幕適配方案也是同樣的。

做者:wildma
原文連接:https://www.jianshu.com/p/1302ad5a4b04
阿里P7移動互聯網架構師進階視頻(每日更新中)免費學習請點擊:https://space.bilibili.com/474380680

相關文章
相關標籤/搜索