In UI development, the label text label is the most commonly used. Android provides TextView to help us display text. The Android Canvas also provides drawText to help us draw the display text when customizing the view.
Take a quick look at this code
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
init {
paint.textSize = 150F
paint.style = Paint.Style.FILL_AND_STROKE
paint.color = Color.parseColor("#FFFFFF")}override fun onDraw(canvas: Canvas?). {
super.onDraw(canvas) canvas? .drawColor(Color.parseColor("#80F14400"))
val textLabel = "Hello World, Hello Python"canvas? .drawText(textLabel,0F.0F, paint)
}
Copy the code
The above code is the simplestdrawText
Use. According to our understanding of the Android coordinate system, it seems that there is no problem. It should draw the text in the upper left corner of the view, and the text is fully displayed.From the real display, the effect is completely inconsistent with what we want. Why does this happen? So let’s seedrawText
Method definition.You can see this in the method commentsdrawText
thex
andy
These are used to define the starting point of text drawing, and this starting pointy
The coordinates are based onbaseline
(Baseline). Want to understandbaseline
To understand the measurement rules of words,canvas
Text measurement rules are usedFontMetrics
Method defined in. whileFontMetrics
fromPaint.getFontMetrics()
To obtain.
Before looking at the definition of FontMetrics, take a look at this graph, which was copied from someone else’s blog.
Leading refers to the extra spacing of rows, i.e. the distance between the ascending bottom line and the descending top line for the two adjacent rows
The FontMetics class mainly defines the measurement properties of the text.
public static class FontMetrics {
/** * The maximum distance above The baseline for The tallest glyph in * The font at a given text size. The maximum distance above the baseline of the highest font in a font. * /
public float top;
/** * The recommended distance above The baseline for single-line delimited text. * /
public float ascent;
/** * The recommended distance below The baseline for Singled out text. * Recommended distance below The baseline for singled out text. * /
public float descent;
/** * The maximum distance below The baseline for The lowest glyph in * The font at a given text size. The maximum distance below the baseline of the lowest font below the font. * /
public float bottom;
/** * The recommended additional space to add between lines of text. * Add additional Spaces between lines of text. * /
public float leading;
}
Copy the code
As you can see from the FontMetrics definition above and from the drawText, baseline is used as a baseline to determine the distance.
You can see thatbaseline
So let’s seebaseline
How do you calculate it?As you can see from the picture,baseline
The size of they
Value is equal to thefontMetrics.bottom + fontMetrics.top -fontMetrics.descent
. Well, you can print it outFontMetrics
To see the output.
val fontMetrics = paint.fontMetrics
Log.e("info"."fontMetrics-->top: " + fontMetrics.top)
Log.e("info"."fontMetrics-->leading: " + fontMetrics.leading)
Log.e("info"."fontMetrics-->ascent: " + fontMetrics.ascent)
Log.e("info"."fontMetrics-->descent: " + fontMetrics.descent)
Log.e("info"."fontMetrics-->bottom: " + fontMetrics.bottom)
Copy the code
E/info: fontMetrics–>top: -157.2 E/info: fontMetrics–>leading: 0.0e /info: fontMetrics–>ascent: -139.2 E/info: Descent: fontMetrics–> Descent: 36.600002 E/info: fontMetrics–> Bottom: 40.65
Comparing the printed results with the graph, it will be found that the starting data is based on the baseline, the data above the baseline is negative and the data below the baseline is positive.
Now that we know what each value means and how the baseline is calculated, we can use the baseline as a guide line and text to draw each attribute, right
val fontMetrics = paint.fontMetrics
val baseline = fontMetrics.bottom + kotlin.math.abs(fontMetrics.top) - fontMetrics.descent
canvas?.save()
// move zero y to baselinecanvas? .translate(0F,
baseline
)
paint.color = Color.BLUE
val textLabel = "Hello,Python"canvas? .drawText(textLabel,0F.0F, paint)
paint.style = Paint.Style.STROKE
/ / draw the toppaint.color = Color.BLUE canvas? .drawLine(0F, fontMetrics.top, width.toFloat(), fontMetrics.top, paint)
paint.color = Color.YELLOW
/ / draw the ascentcanvas? .drawLine(0F, fontMetrics.ascent, width.toFloat(), fontMetrics.ascent, paint)
paint.color = Color.GRAY
/ / draw the descentcanvas? .drawLine(0F, fontMetrics.descent, width.toFloat(), fontMetrics.descent, paint)
paint.color = Color.parseColor("#F15500")
/ / draw the bottomcanvas? .drawLine(0F, fontMetrics.bottom, width.toFloat(), fontMetrics.bottom, paint)
/ / draw the baseline
paint.color = Color.parseColor("#8080FF")
paint.pathEffect = DashPathEffect(floatArrayOf(10F.10F), 0F) canvas? .drawLine(0F.0F, width.toFloat(), 0F, paint) canvas? .restore()Copy the code
If you want to understand the system, welcome to subscribe to my TextView special lecture, so that you can thoroughly understand the principle of TextView drawing, from the perspective of the source code to understand Google design ideas.
Welcome to the Textview – to show you how to draw a Textview