Sizing the font inside a TextView
is one issue that arises often when building an app. Since the app will run on many devices with various screen sizes, it could look awkward on some devices if we use the same font size for all the devices. There are many ways to set the size of the font inside a TextView
so that the text fits well. We explore how to set it so that the text fits in one line and the font size is maximal. We assume that there is no padding inside the TextView
.
We build a utility class, DynamicSizing
, that includes a static
method that works as follows:
▸ It sets the size of the font in the TextView
so that the text fits on one line and that the font size is maximal.
Another possible implementation of this functionality is to subclass TextView
and define the method mentioned previously as a non static
method.
One strategy to compute the optimal font is to start with a very large font, for example of size 200, and decrease the font size by 1 as long as it takes two lines or more to fit the text inside the TextView
, as in the following pseudo-code:
font size = 200 while( text needs 2 or more lines to fit inside TextView ) { decrease font size by 1 }
We can use the getLineCount
method, shown in TABLE B.1, of the TextView
class to access the number of lines that the text occupies within the TextView
. One issue that arises when resizing a View
or a property of a View
dynamically is to have access to the View
’s properties, such as width, height, or the number of lines that the text occupies. If the View has not been displayed yet, the methods getWidth
, getHeight
, and getLineCount
all return 0
. We can call the measure
method of the View
class (see Table B.1) in order to access the width, height, and number of lines of text inside a TextView
. If we call measure
first, then the call to getLineCount
returns the actual number of lines that the text takes inside the TextView
. To obtain width and height information after calling measure
, we should call the getMeasuredWidth
and getMeasuredHeight
methods. The measure
method takes two int
parameters, specifying the type of size constraint that the parent of the View
has imposed or not imposed on it. TABLE B.2 shows three constants of the MeasureSpec
class that we can use to specify values for these two parameters.
TABLE B.1 Selected methods of the View
and TextView
classes
Class | Method | Description |
---|---|---|
View | int getWidth( ) | Returns the width of the View in pixels, 0 if it has not been displayed yet. |
View | int getHeight( ) | Returns the height of the View in pixels, 0 if it has not been displayed yet. |
View | void measure( int widthMeasureSpec, int heightMeasureSpec ) | Called if we want to find out the size of the View; widthMeasureSpec and heightMeasureSpec represent the horizontal and vertical requirement imposed by the parent View. |
View | int getMeasuredWidth( ) | Returns the width of the View in pixels as measured by the call to measure. |
View | int getMeasuredHeight( ) | Returns the height of the View in pixels as measured by the call to measure. |
View | ViewParent getParent( ) | Returns the parent view of this View. |
TextView | int getLineCount( ) | Returns the number of lines of text inside the TextView, 0 if the TextView has not been displayed yet. |
TextView | void setTextSize( int unit, float size ) | Sets the size of the text inside the TextView to size units. |
TextView | void setWidth( int w ) | Sets the width of TextView to w pixels. |
TextView | void setHeight( int h ) | Sets the height of TextView to h pixels. |
EXAMPLE B.1 shows our DynamicSizing
utility class. We declare the MAX_FONT_SIZE
constant, equal to 200
, at line 8. We use it as the starting size for the font before we decrease it by 1
to find the correct value so that the text fits on one line. We also declare another constant, MIN_FONT_SIZE
, whose value is set to 1
(line 9), and we use this value as the minimum font size for the TextView
.
The setFontSizeToFitInView
method, at lines 11–32, accepts a TextView
parameter, tv
, and modifies its font size. It returns its modified font size. We assign the value of MAX_FONT_SIZE
to the variable fontSize
at line 18 and set the font size of tv
to fontSize
at line 19. We use the integer constant COMPLEX_UNIT_SP
from the TypedValue
class as the first argument of the setTextSize
method of the TextView
class to specify the units. It means that the unit is a scaled pixel. TABLE B.3 shows several constants of the TypedValue
class.
TABLE B.2 Constants of the MeasureSpec class
Constant | Description |
---|---|
UNSPECIFIED | Parent has not imposed any constraint on the child View. |
EXACTLY | Parent has determined the exact size of the child View. |
AT_MOST | Parent has determined the maximum size of the child View. |
TABLE B.3 Constants of the TypedValue
class
Constant | Description |
---|---|
COMPLEX_UNIT_IN | Value in inches. |
COMPLEX_UNIT_PX | Value in raw pixels. |
COMPLEX_UNIT_SP | Value in scaled pixels. |
Before we get the number of lines in the text by calling getLineCount
at line 21, we call measure
at line 20, so that getLineCount
does not return 0
. If it does not, we loop at lines 23–28 until the number of lines, stored in the variable lines
, is equal to 1
or the font size goes down to 2
. If for some reason, for example, if the text is very long, the font size reaches size 2
, we exit the loop. This is unlikely to happen, but it is good defensive programming practice to guard against the unexpected. If we get inside the loop and the font size is greater than 2
, it means that the number of lines is greater than 1
, and therefore the font size needs to be reduced. We decrease fontSize
by 1
at line 24, reset the font size of tv
to reflect that at line 25, call measure
at line 26 to reset the measured values, and update lines
at line 27. Since the font size decreases inside the loop, either the value of lines
will reach 1
or the value of fontSize
will reach 2
.
After exiting the loop, we reset the font size of tv
to fontSize – 1
at line 29, to be sure that the text fits on one line within tv
. We return fontSize
at line 31. Note that we do not account for any padding inside the TextView
.
We now build a simple app and edit the activity_main.xml file and the MainActivity
class to test the setFontSizeToFitInView
method of the DynamicSizing
class. EXAMPLE B.2 shows the activity_main.xml file. We give an id to the TextView
at line 15 so we can get a reference to it in the MainActivity
class in order to modify its width text, and the font size of its text. We set the background of the TextView
to yellow at line 16 so we can visualize its bounds.
EXAMPLE B.3 shows the MainActivity
class. At lines 13–14, we retrieve the TextView
. At lines 15–17, we set its width and text. At lines 18–19, we set its font size so that the text inside it fits on one line. We do not need the returned value of setFontSizeToFitInView
so we make the call to setFontSizeToFitInView
as a stand-alone statement.
FIGURE B. 1 shows the app running inside the emulator. Try changing the text (to PRO or PROGRAM, for example) and/or the width (to 300, for example) of the TextView
and test the app again. The font size adjusts accordingly.
3.15.168.199