web-dev-qa-db-ja.com

キャンバスに描画されるテキストの高さを測定する(Android)

テキストの高さを測定する簡単な方法はありますか?私が今やっている方法は、ペイントのmeasureText()を使用して幅を取得し、試行錯誤して値を見つけておおよその高さを取得することです。 FontMetricsもいじっていますが、これらはすべておおよそのメソッドのように見えます。

私はさまざまな解像度に合わせて物事をスケーリングしようとしています。私はそれを行うことができますが、相対的なサイズを決定するための多くの計算を含む非常に冗長なコードになります。私はそれが嫌いです!より良い方法が必要です。

112
Danedo

Paint.getTextBounds() (オブジェクトメソッド)について

126
bramp

必要なものに応じて、高さを測定する方法はさまざまです。

getTextBounds

少量の固定テキストを正確に中央揃えするようなことをしている場合は、おそらくgetTextBoundsが必要です。このように境界矩形を取得できます

Rect bounds = new Rect();
mTextPaint.getTextBounds(mText, 0, mText.length(), bounds);
int height = bounds.height();

次の画像でわかるように、文字列が異なると高さが異なります(赤で表示)。

enter image description here

これらの高さの違いは、テキストが何であっても一定の高さだけが必要な場合に不利になることがあります。次のセクションを参照してください。

Paint.FontMetrics

フォントメトリックからフォントの高さを計算できます。特定のテキスト文字列ではなく、フォントから取得されるため、高さは常に同じです。

Paint.FontMetrics fm = mTextPaint.getFontMetrics();
float height = fm.descent - fm.ascent;

ベースラインは、テキストが置かれている行です。降下は通常、キャラクターが線より下に行く最も遠い位置であり、上昇は通常、キャラクターが線より下に行く最も遠い位置です。高さを取得するには、負の値であるため、アセントを減算する必要があります。 (ベースラインはy=0で、yは画面を小さくします。)

次の画像を見てください。両方の文字列の高さは234.375です。

enter image description here

テキストの高さだけでなく、行の高さが必要な場合は、次のことを実行できます。

float height = fm.bottom - fm.top + fm.leading; // 265.4297

これらは、ラインのbottomおよびtopです。通常、先頭(行間)はゼロですが、とにかく追加する必要があります。

上記の画像は このプロジェクト からのものです。試してみて、フォントメトリックスの動作を確認してください。

StaticLayout

複数行テキストの高さを測定するには、StaticLayoutを使用する必要があります。 this answer で詳細に説明しましたが、この高さを取得する基本的な方法は次のとおりです。

String text = "This is some text. This is some text. This is some text. This is some text. This is some text. This is some text.";

TextPaint myTextPaint = new TextPaint();
myTextPaint.setAntiAlias(true);
myTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
myTextPaint.setColor(0xFF000000);

int width = 200;
Layout.Alignment alignment = Layout.Alignment.ALIGN_NORMAL;
float spacingMultiplier = 1;
float spacingAddition = 0;
boolean includePadding = false;

StaticLayout myStaticLayout = new StaticLayout(text, myTextPaint, width, alignment, spacingMultiplier, spacingAddition, includePadding);

float height = myStaticLayout.getHeight(); 
151
Suragch

@brampの答えは正しいです-部分的に、計算された境界は、0、0の暗黙的な開始座標を持つテキストを完全に含む最小の長方形になるということは言及していません。

これは、例えば「Py」の高さが「py」または「hi」または「oi」または「aw」の高さと異なることを意味します。ピクセル単位で異なる高さが必要なためです。

これは決して古典的なJavaのFontMetricsと同等ではありません。

テキストの幅はそれほど苦痛ではありませんが、高さは苦痛です。

特に、描画されたテキストを垂直方向に中央揃えする必要がある場合は、描画するテキストを使用する代わりに、テキストの境界(引用符なし)を取得してみてください。私のために働く...

ここに私が意味するものがあります:

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);

Paint.setStyle(Paint.Style.FILL);
Paint.setColor(color);
Paint.setTextAlign(Paint.Align.CENTER);
Paint.setTextSize(textSize);

Rect bounds = new Rect();
Paint.getTextBounds("a", 0, 1, bounds);

buffer.drawText(this.myText, canvasWidth >> 1, (canvasHeight + bounds.height()) >> 1, Paint);
// remember x >> 1 is equivalent to x / 2, but works much much faster

テキストの垂直方向の中央揃えは、境界の長方形の垂直方向の中央揃えを意味します。これは、テキスト(キャップ​​、長い文字など)によって異なります。しかし、私たちが実際にやりたいのは、レンダリングされたテキストのベースラインを揃えて、それらが隆起したり溝が開いたりしないようにすることです。したがって、最小文字(たとえば「a」)の中心がわかっている限り、残りのテキストにその配置を再利用できます。これにより、すべてのテキストが中央揃えになり、ベースラインに揃えられます。

82
Nar Gar

高さは、Paint変数に設定したテキストサイズです。

高さを調べる別の方法は

mPaint.getTextSize();
15
kimnod

Android.text.StaticLayoutクラスを使用して必要な境界を指定し、getHeight()を呼び出すことができます。 draw(Canvas)メソッドを呼び出すことにより、テキスト(レイアウトに含まれる)を描画できます。

3
intrepidis

GetTextSize()メソッドを使用して、Paintオブジェクトのテキストサイズを取得できます。例えば:

Paint mTextPaint = new Paint (Paint.ANTI_ALIAS_FLAG);
//use densityMultiplier to take into account different pixel densities
final float densityMultiplier = getContext().getResources()
            .getDisplayMetrics().density;  
mTextPaint.setTextSize(24.0f*densityMultiplier);

//...

float size = mTextPaint.getTextSize();
2
moondroid

代わりにRect.width()Rect.Height()から返されたgetTextBounds()を使用する必要があります。それは私のために働く。

1
Putti