How to draw a Spanned String with Canvas.drawText in Android

admin

Administrator
Staff member
I want to draw a
Code:
SpannedString
to a
Code:
Canvas
.

<a href=" " rel="noreferrer"><img src=" " alt="enter image description here"></a>

Code:
SpannableString spannableString = new SpannableString("Hello World!");
ForegroundColorSpan foregroundSpan = new ForegroundColorSpan(Color.RED);
BackgroundColorSpan backgroundSpan = new BackgroundColorSpan(Color.YELLOW);
spannableString.setSpan(foregroundSpan, 1, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spannableString.setSpan(backgroundSpan, 3, spannableString.length() - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(spannableString);

The above example was drawn using a
Code:
TextView
, which in turn uses a
Code:
Layout
to draw text with spans. I know that <a href="https://stackoverflow.com/a/41870464/3681880">using a
Code:
Layout
is the recommended way</a> to draw text to the canvas. However, I am making my own text layout from scratch, so I need to implement this myself.

Doing something like this doesn't work

Code:
canvas.drawText(spannableString, 0, spannableString.length(), 0, 0, mTextPaint);

because
Code:
drawText
only gets the text from the
Code:
spannableString
, not any of the spans. The drawing colors are handled separately by
Code:
TextPaint
.

How do I use
Code:
canvas.drawText
(or
Code:
drawTextRun
) to draw the span information (specifically foreground and background color here)?

<strong>Related</strong>

<ul>
<li><a href="https://stackoverflow.com/questions...a-spannedstring-or-spannablestring-in-android">How to loop through the spans in a SpannedString or SpannableString in Android</a></li>
<li><a href="https://stackoverflow.com/questions...i-color-text-with-one-call-to-canvas-drawtext">Is it possible to display multi-color text with one call to Canvas.drawText()?</a></li>
</ul>

<strong>Plan for a solution</strong>

<em>I was going to directly do a self answer but this is turning out to be more difficult than I thought. So I will post first and then add an answer whenever I can figure it out. (I would of course welcome anyone to answer first.)</em>

Here are the pieces that I have so far:

<ul>
<li><a href="https://stackoverflow.com/a/43270576/3681880">Draw each span range as a separate text run</a> </li>
<li>Use <a href="https://developer.android.com/refer...loat, float, boolean, android.graphics.Paint)" rel="noreferrer">
Code:
drawTextRun
</a> to draw the text (<a href="http://www.programcreek.com/java-ap...ndroid.graphics.Canvas&amp;method=drawTextRun" rel="noreferrer">examples</a>) (<strong>update</strong>: not added until API 23)</li>
<li>Use <a href="https://developer.android.com/refer...nce(char[], int, int, int, int, boolean, int)" rel="noreferrer">
Code:
getRunAdvance
</a> to measure where to start the next text run (<strong>update</strong>: not added until API 23, use
Code:
measureText
instead)</li>
<li>The background color will probably need to be drawn separately (with
Code:
drawRect
or maybe
Code:
drawPath
? See <a href="https://azzits.wordpress.com/tag/android-drawtext-with-background-color/" rel="noreferrer">here</a>, <a href="https://stackoverflow.com/questions/8242439/how-to-draw-text-with-background-color-using-canvas">here</a>, and <a href="https://stackoverflow.com/questions...background-onto-canvas-to-be-used-as-a-bitmap">here</a>.)</li>
<li>Source code for <a href="https://github.com/android/platform...master/core/java/android/widget/TextView.java" rel="noreferrer">
Code:
TextView
</a>, <a href="https://github.com/android/platform...ster/core/java/android/text/StaticLayout.java" rel="noreferrer">
Code:
StaticLayout
</a>, and <a href="https://android.googlesource.com/pl...+/master/core/java/android/text/TextLine.java" rel="noreferrer">
Code:
TextLine
</a></li>
</ul>