Wrapping long text on an Android Canvas-ThrowExceptions

Exception or error:

I have a custom control that is doing a lot of 2D drawing straight to the canvas.

Some of this drawing is text, so I am using the Canvas.drawText() method.

I want to draw the text within some bounds – a top-left, certain maximum width, and a maximum number of lines. After drawing the text, I want to know how many lines it took.

Is there a built-in function to draw text within bounds doing the splitting sensibly?

If not, is there a standard recipe for doing so?

How to solve:

You can use the android.text.StaticLayout class for this; simply create a StaticLayout for the desired text, alignment, width, etc. and call its draw(Canvas) method to draw to the canvas.

###

You can use Paint.getTextBounds() to measure the size of the entire string or Paint.getTextWidths() to get the width of each character. Then split the string appropriately before drawing it.

###

I had the same problem. One of my first solution is following.

/**
     * This function draws the text on the canvas based on the x-, y-position.
     * If it has to break it into lines it will do it based on the max width
     * provided.
     * 
     * @author Alessandro Giusa
     * @version 0.1, 14.08.2015
     * @param canvas
     *            canvas to draw on
     * @param paint
     *            paint object
     * @param x
     *            x position to draw on canvas
     * @param y
     *            start y-position to draw the text.
     * @param maxWidth
     *            maximal width for break line calculation
     * @param text
     *            text to draw
     */
public static void drawTextAndBreakLine(final Canvas canvas, final Paint paint,
        final float x, final float y, final float maxWidth, final String text) {
    String textToDisplay = text;
    String tempText = "";
    char[] chars;
    float textHeight = paint.descent() - paint.ascent();
    float lastY = y;
    int nextPos = 0;
    int lengthBeforeBreak = textToDisplay.length();
    do {
        lengthBeforeBreak = textToDisplay.length();
        chars = textToDisplay.toCharArray();
        nextPos = paint.breakText(chars, 0, chars.length, maxWidth, null);
        tempText = textToDisplay.substring(0, nextPos);
        textToDisplay = textToDisplay.substring(nextPos, textToDisplay.length());
        canvas.drawText(tempText, x, lastY, paint);
        lastY += textHeight;
    } while(nextPos < lengthBeforeBreak);
}

What is missing:

  • No intelligent break-line mechanism, since it breaks based on the maxWidth

How to call?

    paint.setTextSize(40);
    paint.setColor(Color.WHITE);
    paint.setSubpixelText(true);
    float textHeight = paint.descent() - paint.ascent();
    CanvasUtils.drawTextAndBreakLine(canvas, paint, this.left,
            textHeight, this.displayWidth, this.text);

I have a static class called CanvasUtils where I encapsulate stuff like this. Basically I draw the text within a rectangle. This is the reason textHeight is the height of the text. But you can pass what you want to the function.

Good programming!

Leave a Reply

Your email address will not be published. Required fields are marked *