無論咱們開發者使用哪一個度量單位,最後通過android系統的處理,都是要轉換成像素單位的,也就是px。而在android中,負責實現這一轉換過程的函數以下:java
[java] view plaincopyprint? // 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; }
看完上述兩個函數,有必定基礎的同窗相信已經一目瞭然,不過這裏我仍是作一下詳細介紹:
android
一、 DisplayMetrics是一個封裝了屏幕屬性的數據結構,其中有屏幕的高度、寬度、dpi(每英寸像素個數)、已及數據結構
上面函數中用到的density、scaledDensity等信息;app
二、 特定機型的density是肯定的,其取值取決於dpi,函數
若是dpi == 160, 則density = 1; 佈局
若是dpi == 120, 則density = 0.75; 字體
若是dpi = 320, 則density = 2; spa
依次類推,也就是說code
density = (dpi*1.0)/ 160;開發
三、至於scaleDensity, android源碼中的解釋以下:
[java] view plaincopyprint? /** * 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是運行時肯定的,是會跟這用戶設置的偏好字體大小變化的。
四、至此,咱們就基本明白了sp和dp的區別,在不少android書籍中,都會說到若是是字體的大小開發者應該使
用sp做爲單位,甚至android官方文檔也這麼說,我認爲這純屬是在誤導人,由於sp是運行時肯定的,字體大小
在運行時肯定是有可能引起佈局混亂的。若是想獲得無論用戶如何設置偏好字體大小,咱們開發的應用的字體大
小都不變就應該使用dp,而不是sp。
五、咱們在開發過程當中,常常須要用到這些度量單位的轉換,其實理解這些單位之間的區別以及android對這些單
位的轉換以後,要實現轉換函數是很簡單的了
[java] view plaincopyprint? 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); }