Android下setTextSize的正確使用姿勢

問幾個(gè)問題先

在app/src/main/res/values/dimens.xml中定義尺寸如下:

<dimen name="font1">18sp</dimen>

在代碼中引用此尺寸如下:

mText.setTextSize(18);  // 方法1
mText.setTextSize(getResources().getDimension(R.dimen.font1));  // 方法2
mText.setTextSize(TypedValue.COMPLEX_UNIT_PX,getResources().getDimension(R.dimen.font1));  // 方法3
mText.setTextSize(TypedValue.COMPLEX_UNIT_SP,18);  // 方法4

問題1: 方法1和方法2設(shè)置的文字尺寸大小相同么?
問題2:方法3和方法4設(shè)置的文字尺寸大小相同么?
問題3:方法1和方法4設(shè)置的文字尺寸大小相同么?

如果你能很清楚的給出上面問題的答案,那就沒必要再向下看了;
如果你對以上問題感到模棱兩可的話,請繼續(xù)往下看:

要想解開以上疑惑,其實(shí)主要從以下兩個(gè)方法的源碼入手

setTextSize(...)

進(jìn)入TextView類,找到setTextSize(...)方法,發(fā)現(xiàn)它調(diào)用了另一個(gè)重載方法,注意這里調(diào)用重載方法時(shí)傳入的第一個(gè)參數(shù)是一個(gè)默認(rèn)值 TypedValue.COMPLEX_UNIT_SP,因此方法1和方法4設(shè)置的文字尺寸大小相同.

public void setTextSize(float size) {
    setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
}

public void setTextSize(int unit, float size) {   
    Context c = getContext();    
    Resources r;   
    if (c == null)        
        r = Resources.getSystem();    
    else        
        r = c.getResources();

    setRawTextSize(TypedValue.applyDimension(unit, size, r.getDisplayMetrics()));
}
重載方法中有兩個(gè)方法需要重點(diǎn)看
setRawTextSize(...)方法

通過它的幾個(gè)方法會發(fā)現(xiàn)它的作用就是真正設(shè)置文字大小并刷新顯示:

private void setRawTextSize(float size) {    
    if (size != mTextPaint.getTextSize()) {            
        mTextPaint.setTextSize(size);        
        if (mLayout != null) {            
            nullLayouts();            
            requestLayout();            
            invalidate();        
        }    
    }
}
TypedValue類中的applyDimension(...)方法

根據(jù)傳入的unit單位來處理文字大小,返回的尺寸為px (通過第一個(gè)case條件得知).

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為COMPLEX_UNIT_PX,則會將value直接返回
如果傳入的unit為COMPLEX_UNIT_SP,則會將value處理成px返回

getDimension(...)

進(jìn)入Resources類,找到getDimension(...)方法

public float getDimension(@DimenRes int id) throws NotFoundException {
    synchronized (mAccessLock) {        
        TypedValue value = mTmpValue;        
        if (value == null) {            
            mTmpValue = value = new TypedValue();        
        }        
        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");    
    }
}

這里方法不多,點(diǎn)getValue(...)方法進(jìn)去看會發(fā)現(xiàn)它內(nèi)部又調(diào)用了native方法,這里我無法進(jìn)一步追溯它的實(shí)現(xiàn),不過沒關(guān)系,因?yàn)槲野l(fā)現(xiàn)有個(gè)方法很眼熟那就是:TypedValue.complexToDimension(...) ,進(jìn)入此方法會驚奇的發(fā)現(xiàn)它也調(diào)用了上面講到的applyDimension(...)方法.

public static float complexToDimension(int data, DisplayMetrics metrics){    
    return applyDimension(        
        (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK, complexToFloat(data), metrics);
}

由此可以大膽的猜測 getDimension(...)方法最終也會將數(shù)據(jù)處理成px返回,因此方法3和方法4設(shè)置的文字尺寸大小相同,只是寫法不同而已.

好了,回到開篇提到的四個(gè)問題,可以得出以下結(jié)論:

方法1:文字尺寸以sp為單位,大小為18
方法2:文字尺寸以sp為單位,大小為(18sp轉(zhuǎn)換為px的值)
方法3:文字尺寸以px為單位,大小為(18sp轉(zhuǎn)換為px的值)
方法4:文字尺寸以sp為單位,大小為18

方法1=方法3=方法4!=方法2

至此,文章結(jié)束,希望此文能幫助到你,如果對此文有不同見解,歡迎直接評論!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容