getDimension()、getDimensionPixelOffset()和getDimensionPixelSize()區別詳解


轉自: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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM