Days ago, out PM asked me to draw an animated strike through line over the TextView. While I found nothing available after some search, I decided to make one on my own: ExTextView.
Let’s take a look at the final effect:
My code is here.
I will list some difficulties during the programming and my solutions to them below. By solving these problems, I got myself a better understanding of how Android TextView measures and draws itself.
How to determine the middle position of a line of text?
At the beginning, I took it for granted that the position of strike through should ideally be at the 0.5 of the line height. However, it is not true because TextView gets itself measured with many arguments.
- Top padding of each line.
Each line is drawn with a top padding, which is used to beautify the text layout. Due to the existence of top padding, the position of the strike through line alters from 0.5 of the line height, to the 0.6–0.65 percent of the line height. Moving the strike through line a little bit lower makes the line cross the “belly” of the text instead of the “neck” of the texts.
2. First line padding.
If your TextView has multiple lines, you will find that the top padding of first line differs from the following lines. Then in ExTextView, positions of strike through of the first line are set separately from the other lines, which is 0.6 for the first line and 0.65 for the others. Surely you can modify the position easily on your own.
paddingPercentage = if (firstLine) 0.6F else 0.65F
3. Calculate the position.
Now with lineHeight and paddingPercentage, the calculation can be presented as:
strikePosition = lineHeight * lineIndex + textHeight * paddingPercentage.
The textHeight can be acquired by the Paint of the TextView.
How to do the CutEdge effect?
To cut the age of texts, I naturally use this function to get the text bounds:
textView.getLineBounds(int lineIndex, Rect dest)
Well, that didn’t work because the above method gives back the rect that fill the full width of the TextView. Not the treasure I am looking for.
This problem really cost me some time. While searching brought no luck to me, I turned around to dig the source code. Soon, I noticed that TextView put the real layout work to its mLayout member. The mLayout can be inited as either BoringLayout or StaticLayout according to the number of lines. Then I could get the real bound of a texts by calling
textView.getLayout.getLine[Left, Top, Right, Bottom](int lineIndex)
GOOD NEWS EVERYONE! Now we can get the exact text bounds!
Further work
I am planning to add a Spotlight Painting to the ExTextView. The effect maybe like this:
Please let me you know if you have any questions. :)