APPENDIX B: Setting the Font Size of a TextView Dynamically

Chapter opener image: © Fon_nongkran/Shutterstock

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.

EXAMPLE B.1 The DynamicSizing utility class

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.

EXAMPLE B.2 The activity_main.xml file

EXAMPLE B.3 The MainActivity class

FIGURE B.1 The Test app running inside the emulator

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.168.199