如何垂直对齐文本?

Les*_*zek 46 java android canvas drawtext

目标:纯画布上的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);
}
Run Code Online (Sandbox Code Playgroud)

现在我不知道在标记为drawText的参数中放什么????,即我不知道如何垂直对齐文本.

就像是

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

似乎或多或少有效,但必须有更好的方法.

wes*_*ton 105

实施例到中心上cxcy:

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);
}
Run Code Online (Sandbox Code Playgroud)

为什么不height()/2f一样?

exactCentre()= (top + bottom) / 2f.

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

当这些只会产生相同的结果top0.对于某些尺寸的某些字体或某些尺寸的其他字体,可能会出现这种情况,但并非适用于所有尺寸的所有字体.

  • 1.首先,代码没有考虑文本的对齐方式(例如,如果对齐是CENTER,它将无法工作)2.由于此方法只是在我们实际绘制文本时简单地翻译文本边界的中心,因此它不适合界限(不考虑文本的上升和下降) (3认同)

小智 25

textY = topLeftY + height/2 - (mPaint.descent() + mPaint.ascent()) / 2
Run Code Online (Sandbox Code Playgroud)

从"基线"到"中心"的距离应为 -(mPaint.descent() + mPaint.ascent()) / 2


小智 21

根据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);
}
Run Code Online (Sandbox Code Playgroud)


Pie*_*our 15

由于在Y处绘制文本意味着文本的基线将从原点开始向下Y像素,因此当您希望将文本置于(width, height)维度矩形中时,您需要执行的操作是:

paint.setTextAlign(Paint.Align.CENTER);  // centers horizontally
canvas.drawText(text, width / 2, (height - paint.ascent()) / 2, paint);
Run Code Online (Sandbox Code Playgroud)

请记住,上升是负面的(这解释了减号).

这不考虑下降,这通常是你想要的(上升通常是高于基线的上限).


Ste*_*tes 9

使用mPaint.getTextBounds(),您可以询问绘制时文本的大小,然后使用该信息,您可以计算要绘制它的位置.

  • 请记住,当您说垂直居中的文本时,您可能意味着围绕角色的上升部分,而不是基线.使用Align.CENTER绘制时,Y坐标将以角色基线为中心. (4认同)
  • getTextBounds()属于Paint,而不是Canvas (2认同)

Ext*_*r13 6

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);
}
Run Code Online (Sandbox Code Playgroud)

用法:

PointF p = getTextCenterToDraw(text, rect, paint);
canvas.drawText(text, p.x, p.y, paint);
Run Code Online (Sandbox Code Playgroud)

  • 为什么*0.4f? (11认同)