如何正確設定動態TextView的textSize

codelang發表於2018-03-28

今天測試測出了一個問題,在高解析度下TextView的顯示沒問題,在低解析度出現了字型特別的小,也就是沒適配好。

如何正確設定動態TextView的textSize

左邊的是 768 * 1028 解析度的機子,右邊的是 1440 * 2560 解析度

推薦新聞部分是動態設定的TextView,出現了適配問題,然後來看看我的程式碼

第一次嘗試

    TextView tv = new TextView(mContext);
    tv.setTextSize(PixelUtils.sp2px(getContext(),4));
複製程式碼

這麼寫的思路是,螢幕都是以px為單位,文字大小用sp,我估摸著用sp的文字大小轉換成px設定到螢幕上,剛好適配,方案失敗。

第二次嘗試

    TextView tv = new TextView(mContext);
    tv.setTextSize(getResources().getDimensionPixelSize(R.dimen.sp_14));
複製程式碼

轉換有問題是吧,那我不轉換,我去dimens檔案裡面去取這個sp值,然後設定到介面上。

如何正確設定動態TextView的textSize

我靠,不至於吧,怎麼變這麼大,xml寫14sp的時候可是穩穩的

第三次嘗試

    TextView tv = new TextView(mContext);
    tv.setTextSize(13);
複製程式碼

實在無力了,隨便寫了算了,碰碰運氣,擦,居然可以,牛逼。

如何正確設定動態TextView的textSize


好奇的我就點進setTextSize方法裡面看了下原始碼,這才大悟恍然,先貼原始碼

    @android.view.RemotableViewMethod
    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()));
    }
    
    private void setRawTextSize(float size) {
        if (size != mTextPaint.getTextSize()) {
            mTextPaint.setTextSize(size);
            if (mLayout != null) {
                nullLayouts();
                requestLayout();
                invalidate();
            }
        }
    }
複製程式碼

setTextSize(float size)最終呼叫的是setTextSize(int unit,float size)方法,只是設定了一個預設引數TypedValue.COMPLEX_UNIT_SP,看引數名字是跟sp有關係

然後看setTextSize(int unit,float size)方法,判斷了下當前有沒有context上下文,然後拿到資源Resources,然後看下TypedValue.applyDimension(unit, size, r.getDisplayMetrics())這個方法

    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,來分別計算出不同單位對應的畫素值是多少,跟我們的工具類PixelUtils.sp2px計算方法一模一樣,那些找畫素轉換還在百度和github的,這不都是現成的嘛,不僅僅有dp、sp的,還有pt、in和mm

然後我們回到setTextSize(float size)方法,預設傳遞的TypedValue.COMPLEX_UNIT_SP,這一地方就是,你設定的size,我會幫你當做sp單位,然後轉換成px設定到螢幕上去,和我第一次嘗試的想法一樣,但是第一次為啥會失敗呢?

我們想想,我在呼叫PixelUtils.sp2px的時候進行了一次計算,這裡計算的結果我本來是想當做px用的,沒想到計算出來的結果直接被當做sp來用,然後通過setTextSize又進行了一次sp2px的計算,這個地方錯就錯在了第一次計算,因為第一次不同解析度下計算出來的sp2px是不一樣的,這個時候設定到螢幕上面去,肯定是完美的,但是,setTextSize對我們的計算結果又進行了一次sp2px,導致完美結果出錯,這就是我們為啥出錯了的原因。

第二次嘗試出錯就不說了,通過Resource拿到的dimen大小,最終會被轉換成px單位,就相當於sp2px(14),px都變得老老大了,然後當做sp一樣的去設定,肯定不對。

總結

1、這下知道了為啥TextView要用sp做單位了,就連setTextSize方法預設都是以sp來計算文字大小的。

2、不要相信群裡那些說不看原始碼的,說什麼面試看原始碼就是裝逼耍流氓的,告訴你,不看的話,你就是完蛋,問題都不知道怎麼解決

3、完畢,經理催我做專案了

相關文章