Android中px、sp、dip的區別

剛剛接觸android開發的同學,在做UI開發的時候都會碰到各種度量單位—-px, dp, sp,網上有很多文章講述這三者的不同,當初我剛開始接觸android開發的時候,正是通過網上的這些資料瞭解他們的區別的,但是看完之後仍然不是很明瞭的感覺,究其原因,是因為大部分文章都是從“其然”的角度來闡述的,讓讀者不知其所以然。本文試圖從android實現的角度來闡述這三者的區別。

不管我們開發者使用哪個度量單位,最後經過android系統的處理,都是要轉換成像素單位的,也就是px。而在android中,負責實現這一轉換過程的函數如下:

// TypedValue 中的這個函數負責將dp,sp,px等維度信息轉換成像素

public static int complexToDimensionPixelSize(int data,

        DisplayMetrics metrics)

   {

     final float value = complexToFloat(data);

     final float f = applyDimension(

           (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK,

           value,

           metrics);           // 這個函數負責完成轉換,其實現請往下看

     final int res = (int)(f+0.5f);  // 這裡做瞭一個四舍五入

     if (res != 0) return res;

     if (value == 0) return 0;

     if (value > 0) return 1;

     return -1;

}



// 從這個函數的實現可以看出android系統對dp和sp處理的區別
public static float applyDimension(int unit, float value,

                              DisplayMetrics metrics)

   {

     switch (unit) {

     case COMPLEX_UNIT_PX:

        return value;   // px不需要做轉換

     case COMPLEX_UNIT_DIP:

        return value * metrics.density;   // dp轉換成px

     case COMPLEX_UNIT_SP:

        return value * metrics.scaledDensity;  // sp轉換成px

     case COMPLEX_UNIT_PT:

        return value * metrics.xdpi * (1.0f/72);

     case COMPLEX_UNIT_IN:

        return value * metrics.xdpi;

     case COMPLEX_UNIT_MM:

        return value * metrics.xdpi * (1.0f/25.4f);

     }

     return 0;

}

看完上述兩個函數,有一定基礎的同學相信已經一目瞭然,不過這裡我還是做一下詳細介紹:

1、 DisplayMetrics是一個封裝瞭屏幕屬性的數據結構,其中有屏幕的高度、寬度、dpi(每英寸像素個數)、已及

上面函數中用到的density、scaledDensity等信息;

2、 特定機型的density是確定的,其取值取決於dpi,

如果dpi == 160, 則density = 1;

如果dpi == 120, 則density = 0.75;

如果dpi = 320, 則density = 2;

依次類推,也就是說

density = (dpi*1.0)/ 160;

3、至於scaleDensity, android源碼中的解釋如下:

/**

   * A scaling factor for fonts displayed on the display.  This is the same

   * as {@link #density}, except that it may be adjusted in smaller

   * increments at runtime based on a user preference for the font size.

   */

   public float scaledDensity;

也就是說,這個屬性基本和density屬性一樣,唯一不同的地方是density對於特定機型是確定的,是不會變化的,

而scaleDensity是運行時確定的,是會跟這用戶設置的偏好字體大小變化的。

4、至此,我們就基本明白瞭sp和dp的區別,在很多android書籍中,都會說到如果是字體的大小開發者應該使

用sp作為單位,甚至android官方文檔也這麼說,我認為這純屬是在誤導人,因為sp是運行時確定的,字體大小

在運行時確定是有可能引發佈局混亂的。如果想得到不管用戶如何設置偏好字體大小,我們開發的應用的字體大

小都不變就應該使用dp,而不是sp。

5、我們在開發過程中,經常需要用到這些度量單位的轉換,其實理解這些單位之間的區別以及android對這些單

位的轉換之後,要實現轉換函數是很簡單的瞭

public static final int dp2px(float dp, Resources res)

 {

  return (int) (dp * res.getDisplayMetrics().density + 0.5f);

 }



public static final int sp2px(float sp, Resources res)

 {

  return (int) (sp * res.getDisplayMetrics().scaledDensity+ 0.5f);

 }

發佈留言