Technical Data Questionnaire - novoda/drop-cap GitHub Wiki

Overview of the project. What are its technical capabilities compared to the industry standard?

Develop an Android text based component that is capable of displaying a DropCap. This library focuses on being as close to a real DropCap as possible. Where the DropCap accent and top begin at the same position as the copy text. The DropCap and copy text, font and colour can be specified independently. The component will measure the DropCap during the drawing phase and automatically determine the number of lines the copy must wrap by.

What platforms and tools were used to make it?

Pure Android component

Technical challenges faced (specifically what development required more than routine techniques) and what was engineered to overcome them?

Version 1.1.0

To create a DropCap where the content_description can be specified for a single component. It’s possible to create an approximate DropCap with the use of two TextViews and a LeadingMarginSpan but this suffers from some issues:

Need to know or be able to calculate the number of lines the LeadingMarginSpan needs to wrap. Need to wrap the two views in another to be able to set a global content_description otherwise you’ll have drop cap content description followed by copy. The DropCap will not render at the correct location. The top of the drawn character should match the top of the copy text. Instead it will draw the character taking into account the top of its own font style top and not the copy’s.

To get a true DropCap where the top of the DropCap matches the top of the copy text a custom view is used. The flow is as follows:

Measure the width of the DropCap using the font style and the number of characters required. This is used to determine the width available to the copy text. Create a new Layout representing the copy text with the adjusted width that was just calculated. Use this Layout to calculate the number if lines to span; take the top of each line until it is greater than the DropCap height. Calculate the baseline:

float baseline = dropCapBounds.height() + getPaddingTop();
dropCapBaseline = baseline - dropCapBounds.bottom;

When you consider dropCapBounds.height() is dropCapBounds.bottom - dropCapBounds.top this seems very strange. Normally, in Android, coordinates begin at the top-left, for text it begins at the bottom-left. Here’s the same calculation with some numbers instead:

float baseline = 122 + 26;
dropCapBaseline = 146 - 2;
dropCapBaseline = 144.

The bottom in the case of text represents the text that extends below the baseline, think of the tail of a g character.

Assuming that there is enough lines to wrap the DropCap and that the DropCap and copy fit within the bounds of the total width then the following measurements now occur: Use the DropCap Layout to determine the remaining text and create a new Layout representing this remaining text, using the copy font style. The final measurement is to calculate the copy distance from the viewport top. This is to ensure that the top of the DropCap matches the top of the copy. It’s calculated in the following way:

copyTextPaint.getTextBounds("d", 0, 1, characterBounds);
float dHeight = characterBounds.height();
float lineBaseline = copyStaticLayout.getLineBaseline(0);
return lineBaseline - dHeight;

The character d is used because it represents a standard lowercase character with an ascender. Accents are not included in this calculation because the eye will not be drawn to them and the DropCap will not look out of place compared to them.

Finally, the DropCap is drawn using the calculated baseline and the distance from viewport top.