ターゲット: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;
多かれ少なかれ問題なく動作するように見えますが、より良い方法が必要です。
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
_の場合にのみ同じ結果をもたらします。これは、すべてのサイズの一部のフォント、または一部のサイズのその他のフォントの場合ですが、すべてのサイズのすべてのフォントの場合ではありません。
_textY = topLeftY + height/2 - (mPaint.descent() + mPaint.ascent()) / 2
_
「ベースライン」から「中心」までの距離は-(mPaint.descent() + mPaint.ascent()) / 2
でなければなりません
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);
}
Yでテキストを描画すると、テキストのbaselineがOriginからYピクセル下になることを意味するため、(width, height)
寸法は次のとおりです。
Paint.setTextAlign(Paint.Align.CENTER); // centers horizontally
canvas.drawText(text, width / 2, (height - Paint.ascent()) / 2, Paint);
上昇は負であることに注意してください(マイナス記号の説明)。
これは降下を考慮に入れていません。これは通常、必要なものです(上昇は通常、ベースラインからのキャップの高さです)。
mPaint.getTextBounds()を使用すると、描画時にテキストがどれだけ大きくなるかを尋ねることができ、その情報を使用して、描画する場所を計算できます。
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);
私は自分の問題を解決しようとしたときにこの質問に出くわしましたが、@ 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);
}
これを探している人のための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);
}