2018/02/22

measureText と getTextBounds の違い

Android の android.graphics.Paint にはテキストサイズ計測用のメソッドが2つ用意されています。 Paint#measureText(String)Paint#getTextBounds(String, int, int, Rect) ですが、これらの違いを調べてみました。

measureText の方が少しだけ大きい

結論から言うと、以下の図のように getTextBounds() はテキストがぴったり入る矩形を返すのに対し、measureText() は左右に余白が入ります。

参考

Android Paint: .measureText() vs .getTextBounds() - Stack Overflow

なお、この画像は以下の AndroidFontMetrics というアプリを使って作成しました。 フォントのメトリックスが視覚的に確認できるので便利です。

GitHub - suragch/AndroidFontMetrics: An Android app for measuring and testing FontMetrics

余白は何なのか

getTextBounds() で取得した矩形の left の値は大抵0ではありません。 例えば、上記の図だと left の値は 14 になります1。 この left の値は SkPaint.cpp 中で先頭の文字のグリフによって決定されています。 つまり、上記の例だと、最初の文字が M の場合、それ以降の文字によらず 14 になります。

また、右の余白は最後の文字のグリフで決定し、measureText() - textBounds.right で求められます。

AndroidFontMetrics はちょっと間違っているかもしれない

と、ここまで書いてきて先に紹介した AndroidFontMetrics の動作が間違っているのではないかと気づきました。 AndroidFontMetrics は左右の余白を平均化して中央に配置するようにしており、TextBounds.left の値が反映されていません2

多分、以下のように素直に描画するのが正しいはず。

1
2
3
4
5
6
7
8
9
10
11
--- a/app/src/main/java/net/studymongolian/fontmetrics/FontMetricsView.java
+++ b/app/src/main/java/net/studymongolian/fontmetrics/FontMetricsView.java
@@ -148,7 +148,7 @@ public class FontMetricsView extends View {
             mTextPaint.getTextBounds(mText, 0, mText.length(), mBounds);
 
             // draw vertical line just before the left bounds
-            startX = getPaddingLeft() + mBounds.left - (width - mBounds.width())/2;
+            startX = getPaddingLeft();
             stopX = startX;
             startY = -verticalAdjustment;
             stopY = startY + this.getHeight();

同日追記

一応 Pull Request を出してみた

  1. フォントサイズは 180 
  2. コードを見ると反映されているように見えるのですが、実は逆に打ち消してしまっている 
?

0 件のコメント: