FontMetrics 淡入淺出
Google文件中的描述:
/** * Class that describes the various各種 metrics指標 for a font at a given text size. * Remember, Y values increase going down, so those values will be positive正數, * and values that measure distances距離 going up will be negative負數. This class * is returned by getFontMetrics(). */ public static class FontMetrics { //The maximum distance above the baseline for the tallest glyph in the font at a given text size. public floattop; //【字元頂部】The recommended推薦的 distance above the baseline for singled spaced text. public floatascent; //【字元底部】The recommended distance below the baseline for singled spaced text. public floatdescent; //The maximum distance below the baseline for the lowest glyph in the font at a given text size. public floatbottom; //【字元行間距】The recommended additional額外的 space to add between lines兩行之間 of text. public floatleading; }
該類描述給定文字大小的字型的各種度量。記住,Y值向下增加,所以這些值為正值,測量向上距離的值為負值。此類由GetFontMetrics()返回。
網上找的各種模型圖
要點如下:
- 基準點是baseline
- Ascent是baseline之上至字元最高處的距離
- Descent是baseline之下至字元最低處的距離
- Leading文件說的很含糊,其實是上一行字元的descent到下一行的ascent之間的距離
- Top指的是指的是最高字元到baseline的值,即ascent的最大值
- bottom指的是最下字元到baseline的值,即descent的最大值
為了幫助理解,我特此搜尋了不同的示意圖。對照示意圖,會很容易理解FontMetrics的引數。

圖1

圖2

圖3

圖4

圖5

圖6
Paint的ascent和descent方法--算高度
這兩個是native方法
//Return the distance above (negative) the baseline (ascent) based on the current typeface字型 and text size. public native float ascent(); //Return the distance below (positive) the baseline (descent) based on the current typeface and text size. public native float descent();
可以通過 mPaint.ascent()+ mPaint.descent() 獲取文字高度
Paint的measureText方法--獲取寬度

/** * Return the width of the text. * * @param textThe text to measure. Cannot be null. * @param start The index of the first character to start measuring * @param end1 beyond the index of the last character to measure * @returnThe width of the text */ public float measureText(String text, int start, int end) { if (text == null) throw new IllegalArgumentException("text cannot be null"); if ((start | end | (end - start) | (text.length() - end)) < 0) throw new IndexOutOfBoundsException(); if (text.length() == 0 || start == end) return 0f; if (!mHasCompatScaling) return (float) Math.ceil(native_measureText(text, start, end, mBidiFlags)); final float oldSize = getTextSize(); setTextSize(oldSize*mCompatScaling); float w = native_measureText(text, start, end, mBidiFlags); setTextSize(oldSize); return (float) Math.ceil(w*mInvCompatScaling); }
通過這個方法即可以輕鬆的獲取到文字的的寬度
Paint的getTextBounds方法--獲取邊界

/** * Return in bounds (allocated by the caller 由呼叫者分配) the smallest最小的 rectangle that * encloses圍起來 all of the characters, with an implied origin預設的起始位置 at (0,0). * @param textString to measure and return its bounds * @param start Index of the first char in the string to measure * @param end1 past the last char in the string measure * @param bounds Returns the unioned bounds of all the text. Must be allocated by the caller. */ public void getTextBounds(String text, int start, int end, Rect bounds) { if ((start | end | (end - start) | (text.length() - end)) < 0)throw new IndexOutOfBoundsException(); if (bounds == null) throw new NullPointerException("need bounds Rect"); nativeGetStringBounds(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, bounds); }
這個方法需要提供一個引數 Rect 矩形區域,這個方法將文字的區域傳遞到 Rect
Paint的獲取
比如對於TextView,要通過TextView的getPaint()得到Paint,而不能new一個或者拿其他不相干的Paint
/** * @return the base paint used for the text.Please use this only to * consult查閱 the Paint's properties屬性 and not to change them. */ public TextPaint getPaint() { return mTextPaint; }
如果是在自定義View 中,則可以直接通過Paint呼叫相關方法去獲取文字的寬高等資訊
測試程式碼
public class MainActivity extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String text = "aA bB fF gG"; TextView tv_info = new TextView(this); tv_info.setTextColor(Color.BLUE); tv_info.setBackgroundColor(0x5500ff00); tv_info.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); tv_info.setText(text); setContentView(tv_info); tv_info.measure(0, 0);//必須手動呼叫測量方法,否則getMeasuredHeight獲取不到值。另外,即使測量過了getHeight也獲取不到值 Paint mPaint = tv_info.getPaint(); Log.i("bqt", "ascent()的值為" + mPaint.ascent() + ",descent()的值為" + mPaint.descent());//-33.398438, 8.7890625 Log.i("bqt", "字元的高度為" + (-mPaint.ascent() + mPaint.descent()) + ",字元的長度為" + mPaint.measureText(text));//42.1875,190.0 Log.i("bqt", "測量的高度為" + tv_info.getMeasuredHeight() + ",測量的寬度為" + tv_info.getMeasuredWidth());//49,190 Rect mRect = new Rect(); mPaint.getTextBounds(text, 0, text.length(), mRect); Log.i("bqt", "字元的邊界為" + mRect.left + "," + mRect.top + "," + mRect.right + "," + mRect.bottom);//1,-28,187,8 Log.i("bqt", "字元的高度為" + (mRect.bottom - mRect.top) + ",字元的長度為" + (mRect.right - mRect.left));//36,186 } }
【附錄】

資料圖
需要資料的朋友可以加入Android架構交流QQ群聊:513088520
點選連結加入群聊【Android移動架構總群】: 加入群聊
獲取免費學習視訊,學習大綱另外還有像高階UI、效能優化、架構師課程、NDK、混合式開發(ReactNative+Weex)等Android高階開發資料免費分享。