web-dev-qa-db-ja.com

テキストを垂直方向に揃える方法は?

ターゲット:Android> = 1.6、純粋なキャンバス。

(幅、高さ)の大きな赤い長方形を描画し、その中に黒のHello Worldテキストを描画する関数を書きたいとします。テキストを四角形の中央に視覚的に配置します。試してみましょう:

void drawHelloRectangle(Canvas c, int topLeftX, 
        int topLeftY, int width, int height) {
    Paint mPaint = new Paint();
    // height of 'Hello World'; height*0.7 looks good
    int fontHeight = (int)(height*0.7);

    mPaint.setColor(COLOR_RED);
    mPaint.setStyle(Style.FILL);
    c.drawRect( topLeftX, topLeftY, topLeftX+width, topLeftY+height, mPaint);

    mPaint.setTextSize(fontHeight);
    mPaint.setColor(COLOR_BLACK);
    mPaint.setTextAlign(Align.CENTER);
    c.drawText( "Hello World", topLeftX+width/2, ????, mPaint);
}

これで、????でマークされたdrawTextの引数に何を入れるかわかりません。つまり、テキストを垂直方向に揃える方法がわかりません。

何かのようなもの

???? = topLeftY + height/2 + fontHeight/2-fontHeight/8;

多かれ少なかれ問題なく動作するように見えますが、より良い方法が必要です。

44
Leszek

cxおよびcyを中心とする例:

_private final Rect textBounds = new Rect(); //don't new this up in a draw method

public void drawTextCentred(Canvas canvas, Paint paint, String text, float cx, float cy){
  Paint.getTextBounds(text, 0, text.length(), textBounds);
  canvas.drawText(text, cx - textBounds.exactCenterX(), cy - textBounds.exactCenterY(), Paint);
}
_

height()/2fが同じように機能しないのはなぜですか?

exactCentre() = _(top + bottom) / 2f_。

height()/2f = _(bottom - top) / 2f_

これらは、topが_0_の場合にのみ同じ結果をもたらします。これは、すべてのサイズの一部のフォント、または一部のサイズのその他のフォントの場合ですが、すべてのサイズのすべてのフォントの場合ではありません。

102
weston
_textY = topLeftY + height/2 - (mPaint.descent() + mPaint.ascent()) / 2
_

「ベースライン」から「中心」までの距離は-(mPaint.descent() + mPaint.ascent()) / 2でなければなりません

25
QQchurch

Steelbytesの応答に基づいて、更新されたコードは次のようになります。

void drawHelloRectangle(Canvas c, int topLeftX, int topLeftY, int width, int height) {
    Paint mPaint = new Paint();
    // height of 'Hello World'; height*0.7 looks good
    int fontHeight = (int)(height*0.7);

    mPaint.setColor(COLOR_RED);
    mPaint.setStyle(Style.FILL);
    c.drawRect( topLeftX, topLeftY, topLeftX+width, topLeftY+height, mPaint);

    mPaint.setTextSize(fontHeight);
    mPaint.setColor(COLOR_BLACK);
    mPaint.setTextAlign(Align.CENTER);
    String textToDraw = new String("Hello World");
    Rect bounds = new Rect();
    mPaint.getTextBounds(textToDraw, 0, textToDraw.length(), bounds);
    c.drawText(textToDraw, topLeftX+width/2, topLeftY+height/2+(bounds.bottom-bounds.top)/2, mPaint);
}
21
gauravjain0102

Yでテキストを描画すると、テキストのbaselineがOriginからYピクセル下になることを意味するため、(width, height)寸法は次のとおりです。

Paint.setTextAlign(Paint.Align.CENTER);  // centers horizontally
canvas.drawText(text, width / 2, (height - Paint.ascent()) / 2, Paint);

上昇は負であることに注意してください(マイナス記号の説明)。

これは降下を考慮に入れていません。これは通常、必要なものです(上昇は通常、ベースラインからのキャップの高さです)。

15

mPaint.getTextBounds()を使用すると、描画時にテキストがどれだけ大きくなるかを尋ねることができ、その情報を使用して、描画する場所を計算できます。

9
SteelBytes
public static PointF getTextCenterToDraw(String text, RectF region, Paint paint) {
    Rect textBounds = new Rect();
    Paint.getTextBounds(text, 0, text.length(), textBounds);
    float x = region.centerX() - textBounds.width() * 0.4f;
    float y = region.centerY() + textBounds.height() * 0.4f;
    return new PointF(x, y);
}

使用法:

PointF p = getTextCenterToDraw(text, rect, Paint);
canvas.drawText(text, p.x, p.y, Paint);
7
Exterminator13

私は自分の問題を解決しようとしたときにこの質問に出くわしましたが、@ Westonの答えはうまくいきます。

Kotlinの場合:

private fun drawText(canvas: Canvas) {
    Paint.textSize = 80f
    val text = "Hello!"
    val textBounds = Rect()
    Paint.getTextBounds(text, 0, text.length, textBounds);
    canvas.drawText(text, cx- textBounds.exactCenterX(), cy - textBounds.exactCenterY(), Paint);
    //in case of another Rect as a container:
    //canvas.drawText(text, containerRect.exactCenterX()- textBounds.exactCenterX(), containerRect.exactCenterY() - textBounds.exactCenterY(), Paint);
}
1
N. Osil

これを探している人のためのSkiaSharp C#拡張メソッドがあります

public static void DrawTextCenteredVertically(this SKCanvas canvas, string text, SKPaint Paint, SKPoint point)
{
    var textY = point.Y + (((-Paint.FontMetrics.Ascent + Paint.FontMetrics.Descent) / 2) - Paint.FontMetrics.Descent);
    canvas.DrawText(text, point.X, textY, Paint);
}
0
Benoit Jadinon