1

I have a rectangle that I want to draw text inside. I want the text to be centered vertically and horizontally and I need the text size to changed to fit all characters inside the rectangle. Here is my code:

@Override
public void drawFixedText(String text, Rect rect, Paint paint) {
    paint.setAntiAlias(true);
    paint.setStyle(Paint.Style.FILL);

    int cX = rect.left;
    int cY = rect.top;

    float textSize = paint.getTextSize();
    paint.setTextSize(textSize);

    float textWidth = paint.measureText(text);

    while (textWidth > rect.width())  {
        textSize--;
        paint.setTextSize(textSize);
    }

    //if cX and cY are the origin coordinates of the your rectangle 
    //cX-(textWidth/2) = The x-coordinate of the origin of the text being drawn 
    //cY+(textSize/2) =  The y-coordinate of the origin of the text being drawn 

    canvas.drawText(text, cX-(textWidth/2), cY+(textSize/2), paint);
}

I tried to combine the answers from Calculate text size according to width of text area and Android draw text into rectangle on center and crop it if needed

But it didn't work in that the text is placed to the left of the rectangle instead of inside of it. How can I fix this?

Community
  • 1
  • 1
  • `cX` is the left side of your `Rect`, so you don't want to subtract half the text width from that. Rather, you want to subtract it from the horizontal midpoint of the `Rect`; i.e., `rect.centerX() - (textWidth / 2)`. Also, you need to measure the text width each time after changing the size; that is, `textWidth = paint.measureText(text);` should be inside the loop, too, after the `setTextSize()` call. – Mike M. Aug 06 '16 at 19:35
  • Ok so I did this and it has moved the text seemingly over the top left corner of the rectangle – Popcorn Popper Aug 06 '16 at 19:51
  • Uh, no, that's where it would be with the code you've posted. If you change the x-coordinate as I suggested, the text should be centered on the top side of the `Rect`. Make sure your build is up to date. That is, clean and rebuild after the changes. Also, I just noticed you want it centered vertically, too, so you need to do something similar for the y-coordinate, though using the text size won't center it exactly, if that's a concern. – Mike M. Aug 06 '16 at 20:10
  • Ah, I figured out the problem. My problem was that my text was being centered (Paint.setTextAlign(Align.CENTER)) when I was calling this method (i.e. why it appeared to be far left). So after fixing that, it centered correctly – Popcorn Popper Aug 06 '16 at 20:18
  • Ah, good catch. Yeah, I was assuming a default `Paint` object. – Mike M. Aug 06 '16 at 20:21
  • 1
    Yeah, thanks for your help! If you post an answer with the updated code like stated I will accept it as the answer – Popcorn Popper Aug 06 '16 at 20:23
  • I made a slight correction to the vertical centering, so it's more exact. I'd forgotten `drawText()`'s y-coordinate is the text's baseline. Just FYI. Cheers! – Mike M. Aug 09 '16 at 02:04

1 Answers1

0

First, you need to measure the text width after each time setting its size. Otherwise, you'll end up with an infinite loop if the text starts out wider than the Rect.

while (textWidth > rect.width())  {
    textSize--;
    paint.setTextSize(textSize);
    textWidth = paint.measureText(text);
}

Then, to center the text horizontally, you want to subtract half of the text width from the horizontal midpoint of the Rect, not from its left edge, which is what cX will be in your snippet. That is, replace cX - (textWidth / 2) with rect.centerX() - (textWidth / 2) in the drawText() call.

Furthermore, to center the text vertically, we'll need to do something similar with the y-coordinate. However, using the text size for that will not give the correct result. We need to measure the text's actual height and offset from baseline, which we can do using the Paint#getTextBounds() method.

Altogether, these changes would give something like:

public void drawFixedText(String text, Rect rect, Paint paint) {
    paint.setAntiAlias(true);
    paint.setStyle(Paint.Style.FILL);

    float textSize = paint.getTextSize();
    float textWidth = paint.measureText(text);

    while (textWidth > rect.width())  {
        textSize--;
        paint.setTextSize(textSize);
        textWidth = paint.measureText(text);
    }

    Rect bounds = new Rect();
    paint.getTextBounds(text, 0, text.length(), bounds);

    canvas.drawText(text,
                    rect.centerX() - textWidth / 2,
                    rect.centerY() - (bounds.top + bounds.bottom) / 2,
                    paint);
}

Please note that this assumes a default Paint instance. That is, any properties that affect text alignment have their default values going into this method.

Mike M.
  • 38,532
  • 8
  • 99
  • 95