Multi-Column Text Displays in Android
Recently, I was looking at creating two columns of text in an Android activity. It was not as straightforward as it first appeared to determine the number of characters that would appear in a TextView on screen but there is a simple solution. This article describes how to use the message queue of a TextView to access the on-screen dimensions in order to determine the number of characters that will fit in the TextView in your code.
In Android applications, it is a common practice to load a TextView during the onCreate call to an Activity. For example:
In most applications this works just fine. A problem does arise if you need to determine the height, in pixels, of the TextView to perform more sophisticated actions. As an example, supposed you want to have two TextViews side by side to create a multi-column text screen like in an old-fashion newspaper. The layout for this activity would be:
How to determine where to split up the text for the left and right TextViews? The obvious answer is to determine the height of the TextView and divide by the height of a line of text. Then you can add just enough text to the left TextView and the rest to the right TextView. Easy enough:
However, when you try this you find that tv.getHeight() returns 0 at this time. The reason is that the view for the activity has not been laid out yet so the TextView has no height. How to deal with this? There are several ways but the easiest is to post a Runnable to the TextView’s message queue. The Runnable will be called when after the TextView layout is complete. So our onCreate becomes:
The TextMeasure method called from the Runnable does the actual work of breaking up the text.
The TextMeasure method is called after the TextView has been measured in the LinearLayout. So by deferring the measure of the TextView to the Runnable we have access to the height of the TextView in the layout. Since both TextViews are the same height as specified in the Layout we need only get the height of one of them to determine the number of lines per screen. The breakText method in the TextView’s Paint object will help us determine the number of characters that will fit across the TextView. So the number of total characters in the TextView is approximately textWidth * linesPerScreen.
In a real app, breaking up text is not quite this simple. You would need to account for things like newlines in the text and breaking up text on spaces between words. But I have found that posting the runnable to the TextView’s queue allows access to the information needed to do some pretty sophisticated textual displays.