1. 程式人生 > >安卓螢幕適配方案(根據今日頭條方案,升級版)

安卓螢幕適配方案(根據今日頭條方案,升級版)

前言

螢幕適配方案有很多,比如原生的dp,鴻洋大神的AutoLayout,寬高限定符,今天我用缺點比較小的今日頭條方案

使用效果

測試後可以適配我身邊的所有機型(其他的應該是都可以)

  • 設定Activity後Activity可以適配
  • 設定Activity後Activity內的Fragment可以適配
  • 設定Activity後Activity內的RecyclerView可以適配
  • 設定Activity後Activity彈出的Dialog可以適配

優缺點

優點:適配簡單,無侵入,呼叫簡單,未使用非官方api,不影響效能

缺點:基本可以通過騷操作來避免

使用方式

複製工具類

  1. import android.app.Activity;
  2. import android.util.DisplayMetrics;
  3. /**
  4. * 創 建: lt 2018/8/15--14:45
  5. * 作 用: 使用並優化今日頭條的適配方案的工具類
  6. * 注意事項: 在Activity的onCreate裡,並在setContextView之上呼叫,可以直接放在Base裡
  7. */
  8. public class FitUtil {
  9. private static float width = 750;//todo 手動設定為設計圖的寬,適配將根據寬為基準,也可以設定高,但是推薦設定寬,如果不需要px=dp則不設定也行
  10. private static int dpi = 375
    ;//todo 手動設定設計圖的dpi,不知道可以設計圖的寬除2測試一下
  11. private static float nativeWidth = 0;//真實螢幕的寬,不需要手動改
  12. /**
  13. * 在Activity的onCreate中呼叫,修改該Activity的density,即可完成適配,使用寬高直接使用設計圖上px相等的dp值
  14. *
  15. * @param activity 需要改變的Activity
  16. * @param isPxEqualsDp 是否需要設定為設計圖上的px直接在xml上寫dp值(意思就是不需要自己計算dp值,直接寫設計圖上的px值,並改單位為dp),但開啟後可能需要手動去設定ToolBar的大小,如果不用可以忽略
  17. */
  18. public static void autoFit(Activity activity, boolean isPxEqualsDp) {
  19. if (nativeWidth == 0) {
  20. nativeWidth = activity.getWindowManager().getDefaultDisplay().getWidth();
  21. }
  22. DisplayMetrics displayMetrics = activity.getResources().getDisplayMetrics();
  23. displayMetrics.density = isPxEqualsDp ? nativeWidth / dpi / (width / dpi) : nativeWidth / dpi;
  24. displayMetrics.densityDpi = (int) (displayMetrics.density * 160);
  25. }
  26. }

使用

在Activity的onCreate裡,並在setContextView之上呼叫,可以直接放在Base裡,比如:

  1. public class BaseActivity extends AppCompatActivity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. FitUtil.autoFit(this,true);//this
  6. }
  7. }

手動設定好UI給你的設計圖的寬和dp(請檢視註釋自行計算)

單位用dp,字型單位也用dp,就可以自動適配了

需要注意方法的第二個引數

如果UI給你的圖紙是按照dp為單位,就設定為false,然後頁面上直接寫相應的dp值就ok

如果UI給你的圖紙是按照px為單位,就設定為true,然後頁面上寫對應的px值,但是單位寫成dp,相當於直接從UI設計圖上抄下來,很方便

但是推薦設定為false,如果設計圖紙是px為單位則自行計算,因為設定為true會使其他的三方View變得偏小

某些可以避免的坑

  1. 字型單位的坑,sp可以通過修改scaledDensity屬性來修改,不過為了防止使用者調節字型導致字型顯示不全,所以推薦使用dp,而不用去修改scaledDensity屬性
  2. 聽說8.0手機無效,不過我在自己的8.0手機上可以(華為)
  3. 本方案對純豎屏應用支援較好,若是純橫屏或橫豎屏相交叉的話需要自行修改方法即可

擴充套件

由於px=dp方案留有一些坑(三方View框架也會用到dp值,而部分無法手動去修改),所以該px=dp的方案並不推薦使用,但是若小夥伴又想如此適配,又想使用px=dp方案的話,接下來我會提供一下騷操作供參考

檢視原始碼可知,系統在使用距離值的時候會把所有的單位值轉換為px值來應用,而轉換方法如下:

  1. TypedValue.java下
  2. public static float applyDimension(int unit, float value,
  3. DisplayMetrics metrics)
  4. {
  5. switch (unit) {
  6. case COMPLEX_UNIT_PX:
  7. return value;
  8. case COMPLEX_UNIT_DIP:
  9. return value * metrics.density;
  10. case COMPLEX_UNIT_SP:
  11. return value * metrics.scaledDensity;
  12. case COMPLEX_UNIT_PT:
  13. return value * metrics.xdpi * (1.0f/72);
  14. case COMPLEX_UNIT_IN:
  15. return value * metrics.xdpi;
  16. case COMPLEX_UNIT_MM:
  17. return value * metrics.xdpi * (1.0f/25.4f);
  18. }
  19. return 0;
  20. }

可以看到系統提供了六種單位,上面就是修改了dp的計算係數來適配螢幕,而一些三方框架可能會使用dp,sp甚至是px來給View設定寬高,所以可以將目光放在基本不用的單位上

騷操作來了

我們可以使用in這個單位(英寸),修改方法:

  1. public static void autoFit2(Activity activity, boolean isPxEqualsDp) {
  2. if (nativeWidth == 0) {
  3. nativeWidth = activity.getWindowManager().getDefaultDisplay().getWidth();
  4. }
  5. DisplayMetrics displayMetrics = activity.getResources().getDisplayMetrics();
  6. displayMetrics.xdpi = isPxEqualsDp ? nativeWidth / dpi / (width / dpi) : nativeWidth / dpi;
  7. }

然後所有值抄設計圖上的,單位用in,則可以解決上述問題

親測可以使用,並且適配三方框架,也不會影響到系統控制元件;但,該方案缺點也有,所以該方案僅供參考

  1. 預覽慘不忍睹,因為in單位是英寸,手機才幾英寸,而View的值動不動就是幾十幾百的,預覽時基本上就是一個控制元件佔滿螢幕
  2. 由於本人只是測試了該方案(n多種情況下),但是並沒有正式用在專案上,所以會不會出現奇葩情況也不得而知
  3. 由於修改了xdpi,測試過程中並沒有什麼其他變化,但目前不清楚修改後會不會有其他的影響(檢視原始碼看到引用該值的地方並不多)
  4. 由於該操作屬於比較騷的操作,所以可能不會得到認可(哈哈)

所以上面的幾種方案需要自行選擇判斷