Как выровнять текст по вертикали?

Цель: 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 означает, что исходный текст текста будет заканчиваться 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, px, py, paint);