轉自:http://www.eoeandroid.com/thread-322627-1-1.html?_dsign=91c59c8f
參考:http://www.eoeandroid.com/forum.php?mod=viewthread&tid=322630&page=1&extra=&_dsign=aa409da0
在自定義控件中使用自定義屬性時,經常需要使用java代碼獲取在xml中定義的尺寸,相關有以下三個函數
- getDimension()
- getDimensionPixelOffset()
- getDimensionPixelSize()
(在類TypedArray和類Resources中都有這三個函數,功能類似,TypedArray中的函數是獲取自定義屬性的,Resources中的函數是獲取android預置屬性的)
通常初學者(尤其是洋文不大好的朋友們)看到這三個函數的名稱時會有點不知所雲。反正在我仔細研究前是這樣,getDimensionPixelSize()函數看名稱是獲取像素,那getDimensionPixelOffset()這玩意兒的offset是啥(通常API里不都是 begin, offset, len么)? getDimension()這個函數又是干啥的,和getDimensionPixelSize()有什么區別嗎,是獲取原始的dp值嗎(答案是否定的)?
高手請無視本帖,不太明白的初學者可以往下仔細看看哦~
帶着這些疑惑,看看API reference里的解釋:
- getDimension()是基於當前DisplayMetrics進行轉換,獲取指定資源id對應的尺寸。文檔里並沒說這里返回的就是像素,要注意這個函數的返回值是float,像素肯定是int。
- getDimensionPixelSize()與getDimension()功能類似,不同的是將結果轉換為int,並且小數部分四舍五入。
- getDimensionPixelOffset()與getDimension()功能類似,不同的是將結果轉換為int,並且偏移轉換(offset conversion,函數命名中的offset是這個意思)是直接截斷小數位,即取整(其實就是把float強制轉化為int,注意不是四舍五入哦)。
由此可見,這三個函數返回的都是絕對尺寸,而不是相對尺寸(dp\sp等)。如果getDimension()返回結果是20.5f,那么getDimensionPixelSize()返回結果就是21,getDimensionPixelOffset()返回結果就是20。
到這里本帖就可以結束了,但如果想知道的多一點,還可以看看android的源代碼,來印證上述解釋。
深入源碼,我們可以發現其實這三個函數實現都很像,以Resources類的getDimension()為例
[mw_shl_code=java,true] public float getDimension(int id) throws NotFoundException {
synchronized (mTmpValue) {
TypedValue value = mTmpValue;
getValue(id, value, true);
if (value.type == TypedValue.TYPE_DIMENSION) {
return TypedValue.complexToDimension(value.data, mMetrics);
}
throw new NotFoundException(
"Resource ID #0x" + Integer.toHexString(id) + " type #0x"
+ Integer.toHexString(value.type) + " is not valid");
}
}[/mw_shl_code]
類TypedValue是動態類型數據的容器,主要用於盛放resource的值。上述代碼第4行就是根據resId獲取TypedValue的值,getDimension()、getDimensionPixelOffset()和getDimensionPixelSize()函數體唯一的不同就是第4行:
- getDimension()調用的是TypedValue的complexToDimension方法
- getDimensionPixelSize調用的是TypedValue的complexToDimensionPixelSize方法
- getDimensionPixelOffset調用的是TypedValue的complexToDimensionPixelOffset方法
我們再深入類TypedValue,查看complexToDimension()、complexToDimensionPixelSize()和complexToDimensionPixelOffset()函數的區別,會發現這三個函數體內容還是差不多,以complexToDimension()為例:
[mw_shl_code=java,true] public static float complexToDimension(int data, DisplayMetrics metrics)
{
return applyDimension(
(data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK,
complexToFloat(data),
metrics);
}[/mw_shl_code]
complexToDimensionPixelOffset()與complexToDimension()不同的是將結果進行了強制轉換,相當於直接截斷小數部分;
complexToDimensionPixelSize()是將結果進行四舍五入,四舍五入的代碼就是把結果加上0.5f再進行強制轉換(因為java的float強制轉換為int都是直接舍去小數的;如果大於等於0.5則加上0.5進位,強制轉換后舍去小數相當於五入;如果小於0.5則加上0.5后整數部分不變,強制轉換舍去小數后相當於四舍,java基礎,第一次接觸的新手普及下~)
ok了,簡單的源碼分析完成了。 通過源碼分析,進一步驗證了getDimension()、getDimensionPixelOffset()和getDimensionPixelSize()的區別,大家以后再用到這三個函數的時候就不用發蒙了。在java代碼里很多setWidth(),setHeight()的參數都是像素,即整形,大家根據實際情況,看看如果是四舍五入就調用getDimensionPixelSize(),如果是取整就調用getDimensionPixelOffset()。千萬不要setWidth((int)getDimension()) 這么寫哦!
后記: android並沒有在java代碼中直接獲取xml中定義的dp\sp的值的API,可能是因為google認為沒有必要。但如果實在想得到xml中咱們自己寫的dp或sp的值(例如想在日志里輸出dp\sp什么的),請參見http://www.eoeandroid.com/forum.php?mod=viewthread&tid=322630&page=1&extra=&_dsign=aa409da0