原文地址: https://www.jianshu.com/p/4aa...java
如下是 騷年你的屏幕適配方式該升級了! 系列文章,歡迎轉發以及分享:android
我在前面兩篇文章中詳細介紹了 今日頭條適配方案 和 SmallestWidth 限定符適配方案 的原理,並驗證了它們的可行性,以及總結了它們各自的優缺點,能夠說這兩個方案都是目前比較優秀、比較主流的 Android 屏幕適配方案,並且它們都已經擁有了必定的用戶基數git
可是對於一些才接觸這兩個方案的朋友,確定或多或少仍是不知道如何選擇這兩個方案,我雖然在以前的文章中給出了它們各自的優缺點,可是並無用統一的標準對它們進行更細緻的對比,因此也就沒辦法更形象的體現它們的優劣,那下面我就用統一的標準對它們進行對比,看看它們的對比狀況github
我始終堅決地認爲在這兩個方案中,並不能以單個標準就能評判出誰必定比誰好,由於它們都有各自的優缺點,都不是完美的,從更客觀的角度來看,它們誰都不能成爲最好的那個,只有可能明確了它們各自的優缺點,知道在它們的優缺點裏什麼是我能接受的,什麼是我不能接受的,是否能爲了某些優勢作出某些妥協,從而選擇出一個最適合本身項目的屏幕適配方案面試
單純的爭論誰是最好的 Android 屏幕適配方案沒有任何意義,每一個人的需求不同,站的角度不同,評判標準也不同,你能接受的東西他不必定能接受,你以爲不可接受的東西他卻以爲能夠接受,你有你的理由,他有他的理由,想讓一個觀點讓全部人都能接受太難了!因此我在這裏只是列出它們的對比項和對比結果,儘量的作到客觀,最後的選擇結果請自行決定,若是還有什麼遺漏的對比項,請補充!安全
對比項目 | 對比對象 A | 對比結果 | 對比對象 B |
---|---|---|---|
適配效果(越高越好) | 今日頭條適配方案 | ≈ | SW 限定符適配方案(在未覆蓋的機型上會存在必定的偏差) |
穩定性(越高越好) | 今日頭條適配方案 | < | SW 限定符適配方案 |
靈活性(越高越好) | 今日頭條適配方案 | > | SW 限定符適配方案 |
擴展性(越高越好) | 今日頭條適配方案 | > | SW 限定符適配方案 |
侵入性(越低越好) | 今日頭條適配方案 | < | SW 限定符適配方案 |
使用成本(越低越好) | 今日頭條適配方案 | < | SW 限定符適配方案 |
維護成本(越低越好) | 今日頭條適配方案 | < | SW 限定符適配方案 |
性能損耗 | 今日頭條適配方案沒有性能損耗 | = | SW 限定符適配方案沒有性能損耗 |
反作用 | 今日頭條適配方案會影響一些三方庫和系統控件 | ≈ | SW 限定符適配方案會影響 App 的體積 |
能夠看到 SmallestWidth 限定符適配方案 和 今日頭條適配方案 的適配效果其實都是差很少的,我在前面的文章中也經過公式計算過它們的精確度,SmallestWidth 限定符適配方案 運行在未覆蓋的機型上雖然也能夠適配,可是卻會出現必定的偏差,因此 今日頭條適配方案 的適配精確度確實要比 SmallestWidth 限定符適配方案 略高的,不過只要 SmallestWidth 限定符適配方案 合理的分配資源文件,適配效果的差距應該也不大架構
SmallestWidth 限定符適配方案 主打的是穩定性,在運行過程當中極少會出現安全隱患,適配範圍也可控,不會產生其餘未知的影響,而 今日頭條適配方案 主打的是下降開發成本、提升開發效率,使用上更靈活,也能知足更多的擴展需求,簡單一句話歸納就是,這兩兄弟,一個求穩,一個求快,好了,我就介紹這麼多了,本身選擇吧!app
下面就開始介紹我根據 今日頭條屏幕適配方案 優化的屏幕適配框架 AndroidAutoSize,你們千萬不要認爲,我推出的屏幕適配框架 AndroidAutoSize 是根據 今日頭條屏幕適配方案 優化的,我本人就必定支持 今日頭條屏幕適配方案 是最好的 Android 屏幕適配方案這個觀點,它確實很優秀,但一樣也有不少不足,我最真實的觀點在上面就已經表述咯,至於我爲何要根據 今日頭條屏幕適配方案 再封裝一個屏幕適配框架,無外乎就如下幾點緣由:框架
我建議你們均可以去實際體驗一下 今日頭條屏幕適配方案 和 SmallestWidth 限定符適配方案,感覺下它們的異同,我給的建議是,能夠在項目中先使用 今日頭條屏幕適配方案,感覺下它的使用方式以及適配效果,今日頭條屏幕適配方案 的侵入性很是低,若是在使用過程當中遇到什麼不能解決的問題,立刻能夠切換爲其餘的屏幕適配方案,在切換的過程當中也花費不了多少工做量,試錯成本很是低ide
但若是你在項目中先使用 SmallestWidth 限定符適配方案,以後在使用的過程當中再遇到什麼不能解決的問題,這時想切換爲其餘的屏幕適配方案,這工做量可就大了,每一個 Layout 文件都含有大量的 dimens 引用,改起來這工做量得有多大,想一想都以爲後怕,這就是侵入性過高致使的最致命的問題
若是想體驗 今日頭條屏幕適配方案,千萬不要錯過 AndroidAutoSize 哦!僅需一步便可接入項目,下面是 AndroidAutoSize 的地址:
Github : 您的 Star 是我堅持的動力 ✊
AndroidAutoSize 與 今日頭條屏幕適配方案 的關係,至關於汽車和發動機的關係,今日頭條屏幕適配方案 官方公佈的代碼,只實現了修改系統 density 的相關邏輯,這的確在屏幕適配中起到了最關鍵的做用,但這還遠遠還不夠
要想讓使用者可以更傻瓜式的使用該方案,而且可以應對平常開發中的全部複雜需求,那在架構框架時,還須要考慮 API 的易用性以及合理性、框架的擴展性以及靈活性、功能的全面性、註釋和文檔的易讀性等多個方面的問題
因而我帶着個人這些標準在網上搜尋了好久,發現並無任何一個開源框架或解決方案可以達到個人全部標準,它們大多數還只是停留在將 今日頭條屏幕適配方案 封裝成工具類來引入項目的階段,這樣在功能的擴展上有限制,而且對用戶的使用體驗也很差,而我想作的是一個全面性的產品級屏幕適配框架,這離我最初的構想,差距還很是大,因而我只好本身動手,將個人全部思想實現,這纔有了 AndroidAutoSize
寫完 AndroidAutoSize 框架後,由於對 今日頭條屏幕適配方案 有了更加深刻的理解,因此才寫了 騷年你的屏幕適配方式該升級了!(一)-今日頭條適配方案,以幫助你們更清晰的理解 今日頭條屏幕適配方案
AndroidAutoSize 由於名字和 鴻神 的 AndroidAutoLayout 很是類似,而且在填寫設計圖尺寸的方式上也極爲類似,再加上我寫的屏幕適配系列的文章也發佈在了 鴻神 的公衆號上,因此不少人覺得 AndroidAutoSize 是 鴻神 寫的 AndroidAutoLayout 的升級版,這裏我啼笑皆非 😂,我只好在這裏說一句,你們好,我叫 JessYan,的確能夠理解爲 AndroidAutoSize 是 AndroidAutoLayout 的升級版,可是它是我寫的,關注一波唄
但 AndroidAutoSize 和 AndroidAutoLayout 的原理,卻天差地別,好比 AndroidAutoLayout 只能使用 px 做爲佈局單位,而 AndroidAutoSize 剛好相反,在佈局中 dp、sp、pt、in、mm 全部的單位都能支持,惟獨不支持 px,但這也意味着 AndroidAutoSize 和 AndroidAutoLayout 在項目中能夠共存,互不影響,因此使用 AndroidAutoLayout 的老項目也能夠放心的引入 AndroidAutoSize,慢慢的完成屏幕適配框架的切換
之因此將框架取名爲 AndroidAutoSize,第一,是想致敬 AndroidAutoLayout 對 Android 屏幕適配領域的貢獻,第二,也想成爲在 Android 屏幕適配領域有重要影響力的框架
我在上面就已經說了不少開源框架以及解決方案,只是把 今日頭條屏幕適配方案 簡單的封裝成一個工具類而後引入項目,這時不少人就會說了 今日頭條屏幕適配方案 官方公佈的所有代碼都只有 30 行不到,你不把它封裝成工具類,那封裝成什麼?該怎麼封裝?下面就來看看 AndroidAutoSize 的總體結構
├── external │ ├── ExternalAdaptInfo.java │ ├── ExternalAdaptManager.java │── internal │ ├── CancelAdapt.java │ ├── CustomAdapt.java │── unit │ ├── Subunits.java │ ├── UnitsManager.java │── utils │ ├── AutoSizeUtils.java │ ├── LogUtils.java │ ├── Preconditions.java │ ├── ScreenUtils.java ├── ActivityLifecycleCallbacksImpl.java ├── AutoAdaptStrategy.java ├── AutoSize.java ├── AutoSizeConfig.java ├── DefaultAutoAdaptStrategy.java ├── DisplayMetricsInfo.java ├── FragmentLifecycleCallbacksImpl.java ├── InitProvider.java
AndroidAutoSize 根據 今日頭條屏幕適配方案 官方公佈的 30 行不到的代碼,通過不斷的優化和擴展,發展成瞭如今擁有 18 個類文件,近 2000 行代碼的全面性屏幕適配框架,在迭代的過程當中完善和優化了不少功能,相比 今日頭條屏幕適配方案 官方公佈的原始代碼,AndroidAutoSize 更加穩定、更加易用、更增強大,歡迎閱讀源碼,註釋很是詳細哦!
AndroidAutoSize 在使用上很是簡單,只須要填寫設計圖尺寸這一步便可接入項目,但須要注意的是,AndroidAutoSize 有兩種類型的佈局單位能夠選擇,一個是 主單位 (dp、sp),一個是 副單位 (pt、in、mm),兩種單位面向的應用場景都有不一樣,也都有各自的優缺點
你們能夠根據本身的應用場景在 主單位 和 副單位 中選擇一個做爲佈局單位,建議想引入老項目而且注重穩定性的人羣使用 副單位,只是想試試本框架,隨時可能切換爲其餘屏幕適配方案的人羣使用 主單位
其實 AndroidAutoSize 能夠同時支持 主單位 和 副單位,但 AndroidAutoSize 能夠同時支持 主單位 和 副單位 的目的,只是爲了讓使用者能夠在 主單位 和 副單位 之間靈活切換,由於切換單位的工做量可能很是巨大,不能當即完成,但領導又要求立刻打包上線,這時就能夠起到一個很好的過渡做用
主單位 的 Demo 在 demo
將 AndroidAutoSize 引入項目後,只要在 app 的 AndroidManifest.xml 中填寫上設計圖尺寸,無需其餘過多配置 (若是你沒有其餘自定義需求的話),AndroidAutoSize 便可自動運行,像下面這樣👇
<manifest> <application> <meta-data android:name="design_width_in_dp" android:value="360"/> <meta-data android:name="design_height_in_dp" android:value="640"/> </application> </manifest>
在使用主單位時,design_width_in_dp
和 design_height_in_dp
的單位必須是 dp,若是設計師給你的設計圖,只標註了 px 尺寸 (如今已經有不少 UI 工具能夠自動標註 dp 尺寸了),那請自行根據公式 dp = px / (DPI / 160) 將 px 尺寸轉換爲 dp 尺寸,若是你不知道 DPI 是多少?那請以本身測試機的 DPI 爲準,若是連怎麼獲得設備的 DPI 都不知道?百度吧好伐,若是你實在找不到設備的 DPI 那就直接將 px 尺寸除以 3 或者 2 也是能夠的
若是你只是想使用 AndroidAutoSize 的基礎功能,AndroidAutoSize 的使用方法在這裏就結束了,只須要上面這一步,便可幫助你以最簡單的方式接入 AndroidAutoSize,可是做爲一個全面性的屏幕適配框架,在保證基礎功能的簡易性的同時,也必須保證複雜的需求也能在框架內被解決,從而達到一個小閉環,因此下面介紹的內容全是前人踩坑踩出來的一些必備功能,若是你沒這個需求,或者以爲麻煩,能夠按需查看或者跳過,下面的內容建議和 Demo 配合起來閱讀,效果更佳
design_width_in_dp
和 design_height_in_dp
雖然都須要填寫,可是 AndroidAutoSize 只會將高度和寬度其中的一個做爲基準進行適配,一方做爲基準,另外一方就會變爲備用,默認以寬度爲基準進行適配,能夠經過 AutoSizeConfig#setBaseOnWidth(Boolean) 不停的切換,這意味着最後運行到設備上的佈局效果,在高度和寬度中只有一方能夠和設計圖上如出一轍,另一方會和設計圖出現誤差,爲何不像 AndroidAutoLayout 同樣,高和寬都以設計圖的效果等比例完美呈現呢?這也很簡單,你沒法保證全部設備的高寬比例都和你設計圖上的高寬比例一致,特別是在如今全面屏全面推出的狀況下,若是這裏不這樣作的話,當你的項目運行在與設計圖高寬比例不一致的設備上時,佈局會出現嚴重的變形,這個概率很是大,詳情請看 這裏 不少人有疑惑,爲何使用者只須要在 AndroidManifest.xml 中填寫一下 meta-data 標籤,其餘什麼都不作,AndroidAutoSize 就能自動運行,並在 App 啓動時自動解析 AndroidManifest.xml 中填寫的設計圖尺寸,這裏不少人不敢相信,問我真的只須要填寫下設計圖尺寸框架就能夠正常運行嗎?難道使用了什麼 黑科技?
其實這裏並無用到什麼 黑科技,原理反而很是簡單,只須要聲明一個 ContentProvider,在它的 onCreate 方法中啓動框架便可,在 App 啓動時,系統會在 App 的主進程中自動實例化你聲明的這個 ContentProvider,並調用它的 onCreate 方法,執行時機比 Application#onCreate 還靠前,能夠作一些初始化的工做,get 到了嗎?
這裏須要注意的是,若是你的項目擁有多進程,系統只會在主進程中實例化一個你聲明的 ContentProvider,並不會在其餘非主進程中實例化 ContentProvider,若是在當前進程中 ContentProvider 沒有被實例化,那 ContentProvider#onCreate 就不會被調用,你的初始化代碼在當前進程中也就不會執行,這時就須要在 Application#onCreate 中調用下 ContentProvider#query 執行一下查詢操做,這時 ContentProvider 就會在當前進程中實例化 (每一個進程中只會保證有一個實例),因此應用到框架中就是,若是你須要在多個進程中都進行屏幕適配,那就須要在 Application#onCreate 中調用 AutoSize#initCompatMultiProcess 方法
雖然 AndroidAutoSize 不須要其餘過多的配置,只須要在 AndroidManifest.xml 中填寫下設計圖尺寸就能正常運行,但 AndroidAutoSize 仍是爲你們準備了不少可配置選項,盡最大可能知足你們平常開發中的全部擴展需求
全部的全局配置選項在 Demo 中都有介紹,每一個 API 中也都有詳細的註釋,在這裏就不過多介紹了
在 AndroidManifest.xml 中填寫的設計圖尺寸,是整個項目的全局設計圖尺寸,可是若是某些 Activity 頁面因爲某些緣由,設計師單獨出圖,這個頁面的設計圖尺寸和在 AndroidManifest.xml 中填寫的設計圖尺寸不同該怎麼辦呢?不要急,AndroidAutoSize 已經爲你考慮好了,讓這個頁面的 Activity 實現 CustomAdapt 接口便可實現你的需求,CustomAdapt 接口的第一個方法能夠修改當前頁面的設計圖尺寸,第二個方法能夠切換當前頁面的適配基準,下面的註釋都解釋的很清楚
public class CustomAdaptActivity extends AppCompatActivity implements CustomAdapt { /** * 是否按照寬度進行等比例適配 (爲了保證在高寬比不一樣的屏幕上也能正常適配, 因此只能在寬度和高度之中選擇一個做爲基準進行適配) * * @return {@code true} 爲按照寬度進行適配, {@code false} 爲按照高度進行適配 */ @Override public boolean isBaseOnWidth() { return false; } /** * 這裏使用 iPhone 的設計圖, iPhone 的設計圖尺寸爲 750px * 1334px, 高換算成 dp 爲 667 (1334px / 2 = 667dp) * <p> * 返回設計圖上的設計尺寸, 單位 dp * {@link #getSizeInDp} 須配合 {@link #isBaseOnWidth()} 使用, 規則以下: * 若是 {@link #isBaseOnWidth()} 返回 {@code true}, {@link #getSizeInDp} 則應該返回設計圖的總寬度 * 若是 {@link #isBaseOnWidth()} 返回 {@code false}, {@link #getSizeInDp} 則應該返回設計圖的總高度 * 若是您不須要自定義設計圖上的設計尺寸, 想繼續使用在 AndroidManifest 中填寫的設計圖尺寸, {@link #getSizeInDp} 則返回 {@code 0} * * @return 設計圖上的設計尺寸, 單位 dp */ @Override public float getSizeInDp() { return 667; } }
若是某個 Activity 想放棄適配,讓這個 Activity 實現 CancelAdapt 接口便可,好比修改 density 影響到了老項目中的某些 Activity 頁面的佈局效果,這時就可讓這個 Activity 實現 CancelAdapt 接口
public class CancelAdaptActivity extends AppCompatActivity implements CancelAdapt { }
Fragment 的自定義方式和 Activity 是同樣的,只不過在使用前須要先在 App 初始化時開啓對 Fragment 的支持
AutoSizeConfig.getInstance().setCustomFragment(true);
實現 CustomAdapt
public class CustomAdaptFragment extends Fragment implements CustomAdapt { @Override public boolean isBaseOnWidth() { return false; } @Override public float getSizeInDp() { return 667; } }
實現 CancelAdapt
public class CancelAdaptFragment extends Fragment implements CancelAdapt { }
在使用主單位時可使用 ExternalAdaptManager 來實如今不修改三方庫源碼的狀況下,適配三方庫的全部頁面 (Activity、Fragment)
因爲 AndroidAutoSize 要求須要自定義適配參數或取消適配的頁面必須實現 CustomAdapt、CancelAdapt,這時問題就來了,三方庫是經過遠程依賴的,咱們沒法修改它的源碼,這時咱們怎麼讓三方庫的頁面也能實現自定義適配參數或取消適配呢?別急,這個需求 AndroidAutoSize 也已經爲你考慮好了,固然不會讓你將三方庫下載到本地而後改源碼!
須要注意的是 ExternalAdaptManager 的方法雖然能夠添加任何類,可是隻能支持 Activity、Fragment,而且 ExternalAdaptManager 是支持鏈式調用的,以便於持續添加多個頁面
固然 ExternalAdaptManager 不只能夠對三方庫的頁面使用,也可讓本身項目中的 Activity、Fragment 不用實現 CustomAdapt、CancelAdapt 便可達到自定義適配參數和取消適配的功能
前面已經介紹了 副單位 的應用場景,這裏就直接介紹 副單位 如何使用,副單位 的 Demo 在 demo-subunits
首先和 主單位 同樣也須要先在 app 的 AndroidManifest.xml 中填寫上設計圖尺寸,但和 主單位 不同的是,當在使用 副單位 時 design_width_in_dp
和 design_height_in_dp
的單位不須要必定是 dp,能夠直接填寫設計圖的 px 尺寸,在佈局文件中每一個控件的大小也能夠直接填寫設計圖上標註的 px 尺寸,無需再將 px 轉換爲 dp,這是 副單位的 特性之一,能夠幫助你們提升開發效率
<manifest> <application> <meta-data android:name="design_width_in_dp" android:value="1080"/> <meta-data android:name="design_height_in_dp" android:value="1920"/> </application> </manifest>
因爲 AndroidAutoSize 提供了 pt、in、mm 三種類型的 副單位 供使用者選擇,因此在使用 副單位 時,還須要在 APP 初始化時,經過 UnitsManager#setSupportSubunits(Subunits) 方法選擇一個你喜歡的副單位,而後在佈局文件中使用這個副單位進行佈局,三種類型的副單位,其實效果都是同樣,你們按喜歡的名字選擇便可
因爲使用副單位是爲了完全屏蔽修改 density 所形成的對三方庫頁面、三方庫控件以及系統控件的佈局效果的影響,因此在使用副單位時建議調用 UnitsManager#setSupportDP(false) 和 UnitsManager#setSupportSP(false),關閉 AndroidAutoSize 對 dp 和 sp 的支持,AndroidAutoSize 爲何不在使用 副單位 時默認關閉對 dp、sp 的支持?由於容許同時支持 主單位 和 副單位 能夠幫助使用者在 主單位 和 副單位 之間切換時更好的過渡,這點在前面就已經提到過
UnitsManager 的詳細使用方法,在 demo-subunits 中都有展現,註釋也十分詳細
在使用 副單位 時自定義 Activity 和 Fragment 的方式是和 主單位 是同樣的,這裏就再也不過多介紹了
若是你的項目在使用 副單位 而且關閉了對 主單位 (dp、sp) 的支持,這時 ExternalAdaptManager 對三方庫的頁面是不起做用的,只對本身項目中的頁面起做用,除非三方庫的頁面也使用了副單位 (pt、in、mm) 進行佈局
其實 副單位 之因此能完全屏蔽修改 density 所形成的對三方庫頁面、三方庫控件以及系統控件的佈局效果的影響,就是由於三方庫頁面、三方庫控件以及系統控件基本上使用的都是 dp、sp 進行佈局,因此只要 AndroidAutoSize 關閉了對 dp、sp 的支持,轉而使用 副單位 進行佈局,就能完全屏蔽修改 density 所形成的對三方庫頁面、三方庫控件以及系統控件的佈局效果的影響
但這也一樣意味着使用 副單位 就不能適配三方庫的頁面了,ExternalAdaptManager 也就對三方庫的頁面不起做用了
在開發階段佈局時的實時預覽是一個很重要的環節,不少狀況下 Android Studio 提供的默認預覽設備並不能徹底展現咱們的設計圖,因此咱們就須要本身建立模擬設備,dp、pt、in、mm 這四種單位的模擬設備建立方法請看 這裏
AndroidAutoSize 在經歷了 240+ commit、60+ issues、6 個版本 的洗禮後,逐漸的穩定了下來,已經在上個星期發佈了首個正式版,在這裏要感謝將 AndroidAutoSize 接入到本身項目中的上千個使用者,感謝他們的信賴,AndroidAutoSize 建立的初衷就是爲了讓全部使用 今日頭條屏幕適配方案 的使用者能有一個能夠一塊兒交流、溝通的彙集地,因此後面也會持續的收集並解決 今日頭條屏幕適配方案的常見問題,讓 今日頭條屏幕適配方案 變得更加成熟、穩定
至此本系列的第三篇文章也就完結了,這也預示着這個系列連載的終結,這篇文章建議結合系列的第一篇文章 騷年你的屏幕適配方式該升級了!(一)-今日頭條適配方案 一塊兒看,這樣能夠對 今日頭條屏幕適配方案 有一個更深刻的理解,若是你能將整個系列的文章都所有認真看完,那你對 Android 屏幕適配領域的相關知識絕對會有一個飛速的提高!
當你的項目須要切換某個框架時,你會怎麼去考察、分析、對比現有的開源方案,並有足夠的理由去選擇或優化一個最適合本身項目的方案呢?其實整個系列文章能夠看做是我怎麼去選擇同類型開源方案的過程,你之後當遇到一樣的選擇也能夠參照個人思惟方式去處理,固然若是之後面試官問到你屏幕適配相關的問題,你能將我如何選擇、分析、對比已有方案的過程以及文章中的核心知識點告訴給面試官,那確定比你直接說一句我使用的是某某開源庫有價值得多
如下是 騷年你的屏幕適配方式該升級了! 系列文章,歡迎轉發以及分享:
Hello 我叫 JessYan,若是您喜歡個人文章,能夠在如下平臺關注我
-- The end