Android 101: Typography

One way or another, every developer involves with text and some of us has to go deeper to create some custom drawings. In order to make it right and proper, some terms about text and how the framework provides it, needs to be known.
First and foremost, let’s start with some terms:
Typography is the visual aspect of the text. It uses art and techniques to make the distinction between the same texts.
The word "typography" in English comes from the Greek roots τύπος typos = "impression" and -γραφία -graphia = "writing".
Wikipedia
Font is a specific visual representation of the text. For example: Times New Roman.
Typeface (Font Family) is the set of different variations of the same font. For example: Times New Roman Regular, Times New Roman Bold and Times New Roman Italic etc. The characteristics design of the font doesn’t change.

Glyph is the visual representation of a single character. ie: a
B
;
.
Font metrics

Top: The maximum distance above the baseline for the tallest glyph in the font at a given text size. Top line is usually further in comparison to bottom line due to non-ascii characters. e.g. Á character
Ascent: The recommended distance above the baseline for singled spaced text. Ascent line is usually further in comparison to descent line due to non-ascii characters.
Mean line: The top line for the letters that doesn’t have ascending.
Baseline: This is the line each letters sit upon.
Descent: The recommended distance below the baseline for singled spaced text.
Bottom: The maximum distance below the baseline for the lowest glyph in the font at a given text size.
Leading: The space between the lines, basically the space between bottom of the line and top of the next line.
Line height: The distance between bottom and top.
How to get metrics
Font Metrics
Whenever something is drawn, a paint object is always passed through. It holds color and style information about how to draw. Style holds the typeface information. You can get “ascent, descent, top, bottom, leading” metrics from FontMetrics
object for the given font.
Paint paint = new Paint();
FontMetrics metrics = paint.getFontMetrics();
Note that font metric values are relative, you need to use baseline to get exact position for canvas. For instance: In order to get exact y position for ascent for the given canvas, you need to use baseline.
baseline + metrics.ascent -> Actual y position on the canvas
Paint.getTextBounds()
Returns the bounds the smallest rectangle that encloses all of the characters, with an implied origin at (0,0). Note that, Y values are the opposite of what you would think. Going down is increasing the value and going up to ascent is decreasing.
Rect bounds = new Rect();
Paint paint = new Paint();
String text = "These";
paint.getTextBounds(text, 0, text.length, bounds);
One common mistake would be to assume that once you measure the height for a part of the text, it’ll be the same for the remaining. As you see the below, enclosed boundaries may have different size.

Paint.measureText()
Measures the width of the text by considering the glyph. The width might be different than getTextBounds
, but this value is more accurate. Glyph might have some advancement space, hence there is width differences.
Paint paint = new Paint();
String text = "This";
paint.measureText(text, 0, text.length);

In order to get an accurate width, you can use Paint.measureText
Combine both measureText
and getTextBounds
in order to get accurate values for both height and width.
StaticLayout
Note that above solutions only work for the standard text and single line. If you want to measure any Spannable
or work with multiple lines, consider StaticLayout
. As the name indicates, static layout won’t be changed after it is laid out.
When you convert
Spannable
toString
(ie: .toString), you loose all your spans. You can’t useSpannable
inPaint.getTextBounds
orPaint.measureText
That’s one of the reason you may want to considerStaticLayout
Spannable spannable = new SpannableString("This");
spannable.setSpan(new RelativeSizeSpan(3), 0, 1, SPAN_EXCL_EXCL);TextPaint paint = new TextPaint();
StaticLayout layout = StaticLayout.Builder
.obtain(spannable, 0, text.length(), paint, 1000)
.build();float width = layout.getLineWidth(0); // 36
More options
There are a few other options to measure the text size in different cases. For instance, if the text changes dynamically, you can use DynamicLayout which updates itself when the text changes. Or there is BoringLayout which I never used before.
Some more information about typography

Serif: It’s the ending part in the red rectangle.
Sans Serif: Sans means “without”, sans serif =font without serif.
Tracking: The space between the characters.
Kerning: The space between individual characters to provide a pleasant look. Notice that how V and A are close to each other and how weird it’d look if there was no adjustment.