11

What is the difference between Paint and TextPaint? Can only TextPaint draw text to a canvas?

I've been researching how to draw text on a canvas recently, which leads me to TextPaint. However, while reading the source code I was surprised to learn that there isn't much at all to TextPaint. In fact you don't actually need it to draw text on a canvas. So I am adding this Q&A to make this more clear.

wang willway
  • 415
  • 1
  • 3
  • 16
Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393

2 Answers2

22

TextPaint is a subclass of Paint. However, contrary to what you might guess from these names, the heavy work of drawing the text on the canvas is done by Paint. Thus, this

TextPaint textPaint = new TextPaint();
textPaint.setTextSize(50);
canvas.drawText("some text", 10, 100, textPaint);

and this

Paint paint = new Paint();
paint.setTextSize(50);
canvas.drawText("some text", 10, 100, paint);

actually do the same thing. TextPaint is just a light wrapper around Paint and gives Android some extra data to work with when drawing and measuring text. You can see this in action if you read the TextLine class source code (this class draws a line of text). This is apparently why you have to pass in a TextPaint and not a Paint object when creating something like a StaticLayout.

TextPaint fields

The documentation is pretty sparse on what the "extra data" is here is a little fuller explanation. (Disclamer: By changing these values in a TextPaint, I couldn't actually affect any changes to how the text was drawn in my tests. So take this section with a grain of salt.)

  • baselineShift - The baseline is the line at the base of the text. See this answer for an image. Changing baselineShift causes the baseline to move up or down so it affects how high the text is drawn on a line.
  • bgColor - This is the background color behind the text.
  • density - I assume this is the screen density but I couldn't find it being used in any source code.
  • drawableState - I couldn't find much in the source code except a PFLAG_DRAWABLE_STATE_DIRTY flag, which makes me think this is used to let objects know when they need to be redrawn.
  • linkColor - I can only assume this means what it says, the text color of a link. However, I couldn't find this being used in any source code.

Notes

Community
  • 1
  • 1
Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
  • 2
    Concerning `linkColor`, I noticed that it is being used by [ClickableSpan](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/text/style/ClickableSpan.java) while investigating the option for individual styled / coloured spans in a `Spannable`. – Roland van der Linden Nov 18 '19 at 15:35
1

After looking through the source code slightly, I found the public parameters like baselineShift is actually NOT applied to the canvas when you invoke drawText using the textPaint as parameter but an extra data the TextPaint save for you to retrieve to manually apply to the drawing action.

For example, I want (0, 0) to be the center position of the text I draw, and that's how I usually did.

Example

private val mTextPaint = TextPaint().apply {
    color = Colors.BLACK
    textSize = 14.sp
    isAntiAlias = true
    baselineShift = (textSize / 2 - descent()).toInt()
    textAlign = Paint.Align.CENTER
}
override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    canvas.drawText("Hello World", 0f, mTextPaint.baselineShift.toFloat(), mTextPaint)
}

Note: sp is an extension property in kotlin, which works like the function sp2px(Number sp)
And the (textSize / 2 - descent()).toInt() may not be the most accurate approach to center the text verically, please leave a comment if you have any better approach.

YuTang
  • 1,979
  • 1
  • 5
  • 9