要想使本身的佈局在不一樣設備達到精準空置,理清理順android佈局長度單位之間關係頗有必要,不然你也許會常常撓頭爲何顯示出來的佈局不是本身定義的效果呢,有些東西,雖然基礎,可是弄個透徹也須要花些功夫,廢話很少說,下面開始。 android
1.先了解一下android有支持哪些長度單位:
px: pixels(像素). 不一樣設備顯示效果相同,好比咱們800*480的屏幕寬度就是 800px
dip: device independent pixels(設備獨立像素). 不一樣設備有不一樣的顯示效果,這個和設備硬件有關,一般屏幕大時,density就大,屏幕小時,density就小
屏幕實際分辨率爲240px*400px時,densityDpi=120
屏幕實際分辨率爲320px*533px,densityDpi=160
屏幕實際分辨率爲480px*800px,densityDpi=240
而dip與px之間的換算關係是:
pixs =dips * (densityDpi/160),也就是說當densityDpi=160時,1dip=1px
sp: scaled pixels(放大像素),sp的大小取決於系統metrics.scaledDensity值大小
pt: point,是一個標準的長度單位,1pt=1/72英寸,用於印刷業(基本用不到)
pt與px的換算關係:pixs = pt*xdpi * (1.0f/72);xdpi表示1英寸像素個數
in(英寸)長度單位(基本用不到)
in與px的換算關係:pixs = in*xdpi
mm(毫米)長度單位(基本用不到)
mm與px的換算關係:pixs = mm * xdpi * (1.0f/25.4f)
2.看了上面具體長度單位的含義你會產生一個疑問,不一樣單位換算取決於系統的一些屬性,好比densityDpi的值,xdpi的值,那麼系統這些值在哪裏獲取了,直接看我寫的測試用例:
public void testgetdisplay(){
WindowManager wm = (WindowManager) this.getInstrumentation().getContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics mDisplayMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(mDisplayMetrics);
System.out.println("display.height="+wm.getDefaultDisplay().getHeight());
System.out.println("display.width="+wm.getDefaultDisplay().getWidth());
System.out.println("densityDpi="+mDisplayMetrics.densityDpi);
System.out.println("xdpi="+mDisplayMetrics.xdpi);
System.out.println("density="+mDisplayMetrics.density);
}
3.densityDpi與drawable-(hdpi,mdpi,ldpi)之間的關係
系統drawable有hdpi,mdpi,ldpi三個文件夾下面存放不一樣尺寸的圖片,使用哪一個文件下的文件,與系統densityDpi值是有關係的
densityDpi=120:ldpi
densityDpi=160:mdpi
densityDpi=240:hdpi
前面我又說過densityDpi取決於顯示屏,這樣你就瞭解了爲何不一樣顯示屏WVGA,HVGA,QVGA會採用不一樣drawable-(hdpi,mdpi,ldpi)圖片
分辨率爲240px*400px,densityDpi=120-->QVGA:ldpi
分辨率爲320px*533px,densityDpi=160 -->HVGA:mdpi
分辨率爲480px*800px,densityDpi=240 -->WVGA:WVGA app
4.儘管瞭解上面這些理論值,可是有時候發現設置了不一樣長度單位,可顯示出來的效果卻出人預想,我曾經就碰到過這種撓頭的問題,爲解決這個問題,只有
深刻代碼,一探究竟了。
在深刻代碼前咱們首先要搞清楚一個問題,那就是代碼中全部長度值的單位都是px,
手上沒有現成的例子就以如今我研究的/Launcher2/res/layout-land/workspace_screen.xml爲例,看一個自定義屬性:
launcher:cellWidth="105pt"
該屬性自定義了一個桌面快捷圖標的寬度,若讀者本身測試,本身寫個測試view,設置屬性
android:layout_width="800px"
是同樣的。
當view 被建立的時候,xml中的屬性值存在參數AttributeSet attrs中
public CellLayout(Context context, AttributeSet attrs, int defStyle)
繼續看該構造函數的實現代碼
public CellLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//獲取自定義屬性組CellLayout中的全部自定義屬性,關於自定義屬性,這裏不做展開說明
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
//獲取屬性cellWidth的值,長度單位將轉換爲px
mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
。。。
}
實現長度單位換算的關鍵代碼就在a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10),直接深刻到關鍵代碼:
public int getDimensionPixelSize(int index, int defValue)
public static int complexToDimensionPixelSize(int data,DisplayMetrics metrics)
public static float applyDimension(int unit, float value,DisplayMetrics metrics){
switch (unit) {
case COMPLEX_UNIT_PX:
return value;
case COMPLEX_UNIT_DIP:
return value * metrics.density;
case COMPLEX_UNIT_SP:
return value * metrics.scaledDensity;
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;
}
unit就是指單位類型,這個怎麼來的我沒有,但我想它確定是在解析xml是根據不一樣單位轉換的。 函數