1. 程式人生 > >Android之機型適配

Android之機型適配

Android中的機型適配
在軟體開發的過程中,為了讓軟體在不同的場景下都可以使用,所以機型適配是不可或缺並且非常重要耗時的一個環節.

一:機型適配需要考慮的幾個方面:

1,Android的版本
2.手機廠商
3.螢幕的尺寸
4.網路的制式
5.語言
6.國家
7.硬體裝置
8.執行商
…………………
關於現在要考慮的機型適配的問題,就目前來說,我還只能解決一些方面…嘿嘿….

二:如何進行機型適配

1.Android資源適配基礎

1.在Android的工程下的res目錄下進行裝置效能支援的適配.

我們通過在res目錄下新建不同的資料夾,設定不同的佈局/字串/圖片/語言等等,來適配不同的機型.
1.圖片適配螢幕
2.介面橫豎屏切換螢幕
3.螢幕寬高度大小適配
4.語言的適配

2.資源適配

2.. Android提供了自動的裝置檢測功能,能夠根據當前裝置的一些引數資訊,進行動態的資源的載入,從而實現機型適配;

1.首先介紹圖片的適配,

這裡寫圖片描述
在Android的工程目錄下,我們可以看到有不同的資料夾hdpi mdpi xdpi xxhdpi xxxhdpi,存放著相同的圖片,他是在不同的螢幕的解析度下,顯示不同的圖片.

涉及到的知識點:
1.密度dpi越大,同一個畫素尺寸的圖片顯示的越小;

2.手機的螢幕密度越小(解析度卻低),同一個圖片顯示的就大了。

3.高密度手機使用大圖片;低密度手機用小圖片;

4.dpi的計算 .
dp/sp的概念:
dp/dip:Android中,定義一套單位dp,以mdpi為標準,進行自動
運算的畫素數值;
例如:5dp, 在mdpi的手機上,就是5px
在xhdpi的手機上,就是15px
sp: scalable pixel 可縮放的px, 用於文字的處理.運算規則
和dp相似
px = dp * (dpi / 160) 已知dp求px
已知px 求dp, dp = px / (dpi / 160)

5.以mdpi為基準,進行尺寸的縮放;
縮放規則:
mdpi 1 原始尺寸
ldpi 0.75倍 尺寸
hdpi 1.5倍 尺寸
xhdpi 2倍 尺寸
xxhdpi 3倍
xxxhdpi 4倍

6.目前建議,採用高清大圖進行設計,解析度低的會自動縮小,圖片縮小不會失真.

2.螢幕尺寸的匹配

我們可以在res目錄下,新建values檔案,進行不同螢幕尺寸的適配(small/nomal/large/xlarge),我們可以新建layout-small資料夾,設計不同的佈局,我們也可以在values-small檔案下,新建不同的values資原始檔,在不同的螢幕尺寸下顯示不同的資源.
這裡寫圖片描述

3.語言的匹配

新建不同的values語言檔案,適配不同種語言的Android系統.
這裡寫圖片描述

4.Android3.0之後新型的螢幕尺寸的匹配

1).在android3.0之後出現了一套新的螢幕尺寸適配規則: swXXXdp, wXXXdp, hXXXdp
2).可以控制的程度更細,能夠精確適配;可以覆蓋指定數值以及更大的尺寸
swxxxdp :表示螢幕的最短邊是xxxdp的螢幕,都適配.
wxxxdp:表示平行於地面的邊的寬度,在表示的範圍內,將會進行佈局適配;
如: w240dp; w320dp,w480dp,w600dp; 表示的大小:
[240,320),…[600,………..)
hxxxdp:與sxxxxdp同樣的道理.
sw比w/h的優先順序高

5.有關螢幕大小的計算
// 獲取螢幕的高寬,dp,px
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       TextView textView = (TextView) findViewById(R.id.device_text);
        // DisplayMetrics中儲存的是有關螢幕的相關引數
        DisplayMetrics dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        int w = dm.widthPixels; // 螢幕寬度
        int h = dm.heightPixels; // 螢幕高度
        int densityDpi = dm.densityDpi; // 螢幕dpi()
        float xdpi = dm.xdpi; // x dpi
        float ydpi = dm.ydpi; // y dpi
        // px = dp * (dpi / 160) 已知dp求px
        // 已知px 求dp, dp = px / (dpi / 160)
        // 已知dm.density = dpi / 160
        float wDp = w / dm.density;
        Log.d("TAG", "onCreate: w " + wDp + "dp");
        textView.setText(Float.toString(wDp));
    }

4.注意點

1.使用 wrap_content, match_parent 或者 dp單位尺寸
wrap_content,match_parent以及dp尺寸均會進行縮放,如 100dp 對應 medium dpi,那麼對於hdpi就會放到1.5倍,字型必須使用 sp 單位,因為能夠縮放.
2.不要在程式碼中硬編碼尺寸
因為效能和簡單要求,Android系統內部均使用畫素進行維護,例如在一個裝置上執行 View.getWidth()返回10畫素,不要將這個數值作為硬編碼的常數,因為可能在高密度的裝置上,返回的值可能會是15.
案例:

/**
 * 在程式碼中使用尺寸的方式
 * 需要進行程式碼適配
 */
public class CodeSizeActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_code_size);
        ViewGroup group = (ViewGroup) findViewById(R.id.my_layout);
        TextView textView = new TextView(this);
        // LayoutParams 所有的Android標準容器,都有自己的LayoutParams
        // 控制元件新增到哪種容器型別,就使用這個型別的LayoutParams
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                        (int) dp2px(this, 200),  // 直接寫數值 屬於硬編碼
                        (int) dp2px(this, 50)    // 數字都是 畫素單位,!!! 畫素單位不支援機型適配;
                );
        textView.setLayoutParams(lp);
        textView.setText("Hello World by Zhang sir");
        textView.setBackgroundColor(0xFFb99393);
        group.addView(textView);
    }

    /**
     * 實現機型適配,可以指定數值, 根據手機螢幕密度,
     * 生成畫素單位, 用於程式碼中的尺寸設定
     */
    public static float dp2px(Context context, int dp) {
        DisplayMetrics outMetrics = new DisplayMetrics();
        // 版本適配
        if (Build.VERSION.SDK_INT >= 17) {
            DisplayManager displayManager =
                    (DisplayManager) context.getSystemService(
                            Context.DISPLAY_SERVICE
                    );
            displayManager.getDisplay(0).getMetrics(outMetrics);
        } else {
            WindowManager manager =
                    (WindowManager) context.getSystemService(WINDOW_SERVICE);
            manager.getDefaultDisplay().getMetrics(outMetrics);
        }
        float px = dp * outMetrics.density;
        return px;
    }
}

3.不使用絕對佈局
4.使用修飾符定位尺寸和密度資源
5.程式碼中對畫素進行縮放
6*.利用尺寸資源來優化layout佈局
建議將layout中的尺寸數值,放到獨立的尺寸資原始檔dimens.xml中,這樣就可以利用密度、尺寸來進行螢幕尺寸適配而不用建立多個layout.

4.程式碼中 px向dp的轉化

  /**
     * 可以把這個當做工具類.
     * 實現機型適配,可以指定數值,根據手機螢幕密度
     * 生成畫素單位,用於程式碼中的尺寸設定
     */
    public static float dp2Px(Context context, int dp) {
        DisplayMetrics metrics = new DisplayMetrics();
        if (Build.VERSION.SDK_INT >= 17) {
            DisplayManager manager = (DisplayManager) context.getSystemService(context.DISPLAY_SERVICE);
            manager.getDisplay(0).getMetrics(metrics);
        } else {
            WindowManager manager = ((WindowManager) context.getSystemService(WINDOW_SERVICE));
            manager.getDefaultDisplay().getMetrics(metrics);
        }
        float px = dp * metrics.density;
        return px;
    }
5.在版本檢查時可能遇到的問題
1. 機型適配中的版本適配,使用數字來進行判斷的.
    因為在SDK中是有些錯誤的地方
     if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {        
        }
會直接崩潰
Build.VERSION_CODES.N:在AndroidAPI1出現的,在Android5.0的手機會找不到這個變數.因為Android5.0找不到這個變數

2.if (Build.VERSION.SDK_INT >= 24) {
            android.icu.text.SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
        } else {
            java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("yyyy年MM月dd日");
        }
 java中採用堆疊的方式來儲存類,在載入類之前,會檢查所有的類是否存在;所以對於程式,如果有上述程式碼,會直接崩潰
 Android中不會檢查所有的類,會執行到 if (Build.VERSION.SDK_INT >= 24) 再去載入類

3.硬體適配

在清單檔案中使用<uses-feature>,生命硬體所需要的許可權
<uses-feature>一般只對你的APP釋出在GooglePlay的時候其作用,它協助GooglePlay來過濾您的應用程式,比如你明確的在你的程式清單中描述了你的程式必須使用哪些硬體或者軟體相關的功能,則如果某些裝置在GooglePlay上搜索應用時或者在某個程式的詳情頁上就會過濾掉不支援你的裝置的程式。

要區別<uses-featrue>和<uses-permisstion>,你聲明瞭一個<uses-featrue android="android.hardware.camera" />並不代表你就可以不寫<android:name="android.permission.CAMERA"/>許可權說明了,我在第1點其實已經說了,<uses-featrue>其實是供GooglePlay用的,而<uses-permisstion>是供你的Android系統使用的,你想使用某個硬體裝置或者軟體功能就必須申請這個許可權。