1. 程式人生 > >"Android 螢幕適配"-Android面試必問"精華技能點"彙總

"Android 螢幕適配"-Android面試必問"精華技能點"彙總

目錄:

1. 螢幕適配的方式都有哪些?

1.1 方式之-dp

1.1.1 名詞解釋:

  • 解析度

    480*800,1280*720,表示畫素點的總和

  • px(pix)-畫素

    是螢幕裡的最小單元

  • dpi-畫素密度

    • 每英寸螢幕具有的畫素數量,畫素密度越大,細節越豐富
    • 公式:畫素密度 = √{(長度畫素數^2+寬度畫素數^2)}/ 螢幕尺寸
    • 尺寸單位為:英寸;螢幕尺寸為:對角線長度(如下圖)
      這裡寫圖片描述

1.1.2 res資料夾下的目錄分類

(如圖)
這裡寫圖片描述
應用查詢圖片的順序:

先從自己開始(沒有)->逐個就往高的找(沒有)->就往比自己低的

1.1.3 Android中的畫素密度/解析度/dp和px的關係

型別 dip 解析度 dp和px比例
ldip 120 240*320 1dp = 0.75px
mdip(標準) 160 320*480 1dp = 1px
hdip 240 480*800 1dp = 1.75px
xhdip 320 720*1280 1dp = 2px
xxhdip 480 1080*1920 1dp = 3px

比例圖如下:
這裡寫圖片描述

  • 由上面的標準mdip,那麼如果在320*480的手機上,只需要dp就等效於px,因為1:1
  • 我們在程式碼運算過程中經常要做dp和px的互換,根據上面的比例特點.我們只需通過獲取資源.獲取螢幕解析度.獲取比例即可
/*
       density   解析度       dp和px的轉換
ldip    120     240*320     1dp = 0.75px
mdip    160     320*480     1dp = 1px
hdip    240     480*800     1dp = 1.5px
xhdip   320     720*1280    1dp = 2px
xxhdip  480     1080*1920   1dp = 3px

px和dip的轉換,只需獲取比例值即可;得出dp和px
參考標準的mhdip,額算出其他:pixels=dips*(density/160)
如果是240*320的求得density肯定是1;
1.獲取比例值-自動根據當前的手機獲取比例值
(不同解析度得到的不同,比如我的模擬器720*1280返回2)
(PS:傳入dp得px:乘以比例即可;傳入px得dp:除以比例即可),寫成工具類
2.四捨五入

*/
public class DensityUtil { /** * 根據手機的解析度從 dip 的單位 轉成為 px(畫素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * 根據手機的解析度從 px(畫素) 的單位 轉成為 dp */ public static int px2dip(Context context, float pxValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (pxValue / scale + 0.5f); } }

1.1.4佈局裡的160dp和180dp的

160dp:

  • 設定一個按鈕的寬度為160dp,在320*480解析度的機器裡,那麼正好是一半(因為1:1)
  • 在240*320的機器裡,正好也顯示一半,因為(1:0.75),160dp = 120px
  • 在480*800的機器裡,也是一半,因為(1:1.5).160dp = 240px
  • 所以在以上三種解析度下設定多少dp是等效的,歸為一檔.
    <Button
        android:background="#ff0000"
        android:layout_width="60dp"
        android:layout_height="wrap_content"/>
    <Button
        android:background="#00ff00"
        android:layout_width="100dp"
        android:layout_height="wrap_content"/>

三種分辨率同樣的程式碼都顯示這樣的效果:
這裡寫圖片描述

180dp:

  • 如果將上面的160dp,放到720*1280或者1920 *1080,那麼得到的效果和以上機器是不同的
  • 設定180dp寬度的按鈕,在這兩者裡面的效果是一樣的
  • 因為:720*1280(比例是:1:2)所以180dp = 360px,就是一半
  • 1920*1080(比例是:1:3)所以180dp = 540px,也是一半
  • 所以這兩種解析度下設定的dp是等效的,也是一檔
    <Button
        android:background="#ff0000"
        android:layout_width="80dp"
        android:layout_height="wrap_content"/>
    <Button
        android:background="#00ff00"
        android:layout_width="100dp"
        android:layout_height="wrap_content"/>

兩種解析度下都顯示同樣效果
這裡寫圖片描述

2.方式之-dimens(尺寸)

  • (PS:根據上一節的160dp和180dp的講解,我們現在通過自動dimens解決自動適配問題)
  • 1.在res目錄下有預設的values資料夾和dimens.xml檔案
  • 2.為了自動適配1280 *720和1920 *1080解析度,我們分邊建立各自的資料夾
    • values-1280x720(eclipase寫法),Android Studio寫成values-w320dp
      這裡寫圖片描述
  • 3.把剛才的dimens.xml複製一份到目標資料夾

    • 預設的dimens.xml寫成160dp,移到新檔案的定義成180dp;
      這裡寫圖片描述
  • 4.最後在佈局檔案中寫單位大小時,用@dimens/width即可,自動根據螢幕靈活呼叫
    這裡寫圖片描述
    (PS:因為有預設的和指定各種解析度(另外寫1920*1080的,雖然和720等效,但是還是要寫,否則他就用預設的了)的資料夾,所以找不到指定的就用預設的)

3.方式之-layout

  • 原理和上述情況一樣,些不同的layout,會根據解析度自動找到合適的layout
    這裡寫圖片描述

4.方式之-程式碼適配

  • 需求:通過程式碼設定,讓一個TextView的寬和高都為螢幕的一半;
  • 初始:佈局是預設的包裹,如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context=".MainActivity">
    <!-- 現在是預設的包裹 -->
    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#e18080"
        android:text="hello_world"/>
</RelativeLayout>

這裡寫圖片描述
* 步驟:
* 1.獲取tv控制元件
* 2.獲取當前機器的解析度.
* 3.新建一個和跟佈局一樣(根是線性就線性,是關係就設定關係)的引數,構造傳入長和寬(解析度的一半)
* 4.再讓tv控制元件設定引數即可.
*程式碼如下:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //1.
        TextView tv = (TextView) findViewById(R.id.tv);
        //2.
        int height = getWindowManager().getDefaultDisplay().getHeight();
        int width = getWindowManager().getDefaultDisplay().getWidth();
        //3.
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams((int) ((float)width/2+0.5), (int) ((float)height/2+0.5));
        //4.
        tv.setLayoutParams(params);
    }
}

效果:
這裡寫圖片描述

5.方式之-weight權重

(PS:必須是線性佈局)

1.多個相對的標準權重

  • 如果是橫向:把高度設定為0dp

  • 如果是豎向:把寬度設定為0dp

  • 然後色字不同控制元件所佔的權重

    <Button
        android:layout_weight="1"
        android:text="bt1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"/>
    <Button
        android:text="bt2"
        android:layout_weight="2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"/>
 </LinearLayout>

效果:
這裡寫圖片描述

2.單個相對父佈局的權重

  • 1.設定父佈局的總權重:SumWeight
  • 2.設定自己的所佔的權重即可
<LinearLayout
    android:weightSum="3"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <Button
        android:layout_weight="2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="bt1"/>
</LinearLayout>

效果:
這裡寫圖片描述

3.自動權重

  • 想讓前面的完全填充,並且設定權重
  • 然後後面的用包裹即可
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <EditText
        android:text="請輸入內容"
        android:layout_weight="1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="輸出"/>
</LinearLayout>

效果如下:
這裡寫圖片描述

二.螢幕適配的處理技巧都有哪些?

橫豎屏的切換

(正常情況下,每次橫豎屏切換都會導致Activity的重新建立)

  • 1.在活動銷燬前儲存活動狀態(重寫onSaveInstanceState方法),可以參考前面我們講的思維.
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //切換屏幕後獲取資訊
    if (savedInstanceState != null) {
        System.out.println(savedInstanceState.get("height")+"-------");
        System.out.println(savedInstanceState.get("width")+"-------");
    }
}
    //儲存資訊
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putInt("height", 100);
        outState.putInt("width", 50);
        super.onSaveInstanceState(outState);
    }
  • 2.在清單檔案把方向寫死:

    • android:screenOrientation=”portrait”(landscape是橫向,portrait是縱向)
  • 3.如果不想重新讓Activity呼叫,就設定配置更改

    • 在清單檔案設定三個引數:

      • 方向|按鍵隱藏|螢幕尺寸

        android:configChanges="orientation|keyboardHidden|screenSize"
        
    • 另外重寫Activity裡的更改方法

      • 如果切換橫豎屏,之後重新呼叫這個方法
@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
        //橫向就幹嘛 TODO
    } 
    else if(this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
        //豎向就幹嘛 TODO
    }
}

權重的反比例

經過改善一般我們都是設定0dp,然後使用權重,佔多少就佔用多少部分

如果反比例,比如按鈕A權重是1,按鈕B是2,那麼就反過來了,程式碼和效果圖如下.
就是不用0dp,而改用填充

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="bt1"/>

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:text="bt2"/>
    </LinearLayout>

這裡寫圖片描述