7

I tried to write some text on a surface view I created. It works fine, if title is false, and there is no linebreak added to the text. But if I add a title and therefore a linebreak, the linebreak isn't printed as expected, but instead there is this symbol [] printed.

Any hints why?

@Override
public void drawObject() {
String text = "";
if (title) {
   text = getGameBoard().getGame().getForeignProfile().getName() + "\n";
}
text = text + getScoreAsString();
getGameBoard().getCanvas().drawText(text, 0, text.length(), getPosition().getX(), getPosition().getY(), getPaint());
}

5 Answers5

27

You could try something like the following to draw text with linebreaks:

Rect bounds = new Rect();
void drawString(Canvas canvas, Paint paint, String str, int x, int y) {
    String[] lines = str.split("\n");

    int yoff = 0;
    for (int i = 0; i < lines.length; ++i) {
        canvas.drawText(lines[i], x, y + yoff, paint);
        paint.getTextBounds(lines[i], 0, lines[i].length(), bounds);
        yoff += bounds.height();
    }
}
dbotha
  • 1,501
  • 4
  • 20
  • 38
11

dee's answer is brilliant. The code below is based on dee's answer, but with some amendments for personal preferences:

  1. Call it drawMultilineText (as it's sort of equivalent to drawText
  2. Put the parameters in the same order as drawText (text, x, y, paint and canvas on the end)
  3. Get the line height once at the start as the height returned from the bounds depends on the height of the letters, i.e. e is not as tall as E
  4. Add 20% height gap between lines

    void drawMultilineText(String str, int x, int y, Paint paint, Canvas canvas) {
        int      lineHeight = 0;
        int      yoffset    = 0;
        String[] lines      = str.split("\n");
    
        // set height of each line (height of text + 20%)
        paint.getTextBounds("Ig", 0, 2, mBounds);
        lineHeight = (int) ((float) mBounds.height() * 1.2);
        // draw each line
        for (int i = 0; i < lines.length; ++i) {
            canvas.drawText(lines[i], x, y + yoffset, paint);
            yoffset = yoffset + lineHeight;
        }
    }
    
FrinkTheBrave
  • 3,894
  • 10
  • 46
  • 55
4

Continuing to improve on both Dee's and FrinkTheBrave's answers. I've added a Rect to the method to allow for drawing within particular width area. Will look at modifying it to select an appropriate font size and ensure it fits within the correct height area.

This will let you specify the width of the lines that you want to write which is very useful for breaking up an unformatted string of text into similar length lines and drawing them to a canvas.

    private void drawMultilineText(String str, int x, int y, Paint paint, Canvas canvas, int fontSize, Rect drawSpace) {
    int      lineHeight = 0;
    int      yoffset    = 0;
    String[] lines      = str.split(" ");

    // set height of each line (height of text + 20%)
    lineHeight = (int) (calculateHeightFromFontSize(str, fontSize) * 1.2);
    // draw each line
    String line = "";
    for (int i = 0; i < lines.length; ++i) {

        if(calculateWidthFromFontSize(line + " " + lines[i], fontSize) <= drawSpace.width()){
            line = line + " " + lines[i];

        }else{
            canvas.drawText(line, x, y + yoffset, paint);
            yoffset = yoffset + lineHeight;
            line = lines[i];
        }
    }
    canvas.drawText(line, x, y + yoffset, paint);

}

private int calculateWidthFromFontSize(String testString, int currentSize)
{
    Rect bounds = new Rect();
    Paint paint = new Paint();
    paint.setTextSize(currentSize);
    paint.getTextBounds(testString, 0, testString.length(), bounds);

    return (int) Math.ceil( bounds.width());
}

private int calculateHeightFromFontSize(String testString, int currentSize)
{
    Rect bounds = new Rect();
    Paint paint = new Paint();
    paint.setTextSize(currentSize);
    paint.getTextBounds(testString, 0, testString.length(), bounds);

    return (int) Math.ceil( bounds.height());
}

This answer includes this excellent code snippet found here in a previous answer by user850688 https://stackoverflow.com/a/11353080/1759409

Community
  • 1
  • 1
Music Monkey
  • 340
  • 4
  • 15
  • and drawSpace would be...? – desgraci Mar 22 '13 at 16:58
  • drawSpace is a Rect variable that you send to the method so that the method knows how large an area is available to be filled with text. – Music Monkey Mar 24 '13 at 11:07
  • @MusicMonkey isn't the height of each line the exact same as the font size? – android developer Jul 11 '13 at 14:21
  • @android developer yes it is. But for text to look naturally spaced our eye normally works on spacing of approximately 20% above and below... Otherwise each line of text will appear to touch the line above and below. I could rewrite that line again so that linespacing can be passed in as a constant but I found that 'x 1.2' gave me a consistent and pleasant visual layout. – Music Monkey Jul 11 '13 at 23:18
1

The [] symbol is probably your newline character. For whatever reason, drawText() doesn't know how to handle newlines.

Either strip the newline, or call drawText() twice with an offset Y-position to simulate a newline.

Trevor Johns
  • 15,682
  • 3
  • 55
  • 54
0

And I also add and ellipsize for each line:

Rect mBounds = new Rect();
void drawMultiLineString(Canvas canvas, TextPaint paint, String str, Rect drawingRect) {
    int lineHeight = 0;
    int yOffset    = 0;

    String[] lines = str.split("\n");
    for (String line : lines) {
        CharSequence txt = TextUtils.ellipsize(line, mTextPaint, drawingRect.right - drawingRect.left, TextUtils.TruncateAt.END);
        canvas.drawText(txt, 0, txt.length(), drawingRect.left, drawingRect.top + yOffset, paint);
        paint.getTextBounds(line, 0, line.length(), mBounds);
        lineHeight = (int) ((float) mBounds.height() * 1.2);
        yOffset += lineHeight;
    }
}
Parissa Kalaee
  • 606
  • 1
  • 9
  • 17