Chapter 42

Fonts

The question you'll inevitably get when developing any type of application is, “Hey, can we change this font?” The answer depends on which fonts come with the platform, whether you can add other fonts, and how fonts are applied to the widget or whatever needs the font change. Android is no different. It comes with some fonts, plus a means for adding new fonts. However, as with any new environment, there are a few idiosyncrasies to deal with, as described in this chapter.

Love the One You're With

Android natively knows three fonts, by the shorthand names sans, serif, and monospace. These fonts are actually the Droid series of fonts, created for the Open Handset Alliance by Ascender Corp. (www.ascendercorp.com/), a division of Monotype Imaging. To use these three fonts, you can just reference them in your layout XML, such as the following layout from the Fonts/FontSampler sample project:

<?xml version="1.0" encoding="utf-8"?>
<TableLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:stretchColumns="1">
  <TableRow>
    <TextView
      android:text="sans:"
      android:layout_marginRight="4dip"
      android:textSize="20sp"
    />
    <TextView
      android:id="@+id/sans"
      android:text="Hello, world!"
      android:typeface="sans"
      android:textSize="20sp"
    />
  </TableRow>
  <TableRow>
    <TextView
      android:text="serif:"
      android:layout_marginRight="4dip"
      android:textSize="20sp"
    />
    <TextView
      android:id="@+id/serif"
      android:text="Hello, world!"
      android:typeface="serif"
      android:textSize="20sp"
    />
  </TableRow>
  <TableRow>
    <TextView
      android:text="monospace:"
      android:layout_marginRight="4dip"
      android:textSize="20sp"
    />
  <TextView
      android:id="@+id/monospace"
      android:text="Hello, world!"
      android:typeface="monospace"
      android:textSize="20sp"
    />
  </TableRow>
  <TableRow>
    <TextView
      android:text="Custom:"
      android:layout_marginRight="4dip"
      android:textSize="20sp"
    />
    <TextView
      android:id="@+id/custom"
      android:text="Hello, world!"
      android:textSize="20sp"
    />
  </TableRow>
  <TableRowandroid:id="@+id/filerow">
    <TextView
      android:text="Custom from File:"
      android:layout_marginRight="4dip"
      android:textSize="20sp"
    />
    <TextView
      android:id="@+id/file"
      android:text="Hello, world!"
      android:textSize="20sp"
    />
  </TableRow>
</TableLayout>

This layout builds a table showing short samples of five fonts. Notice that the first three have the android:typeface attribute, whose value is one of the three built-in font faces (e.g., “sans"”).

Additional Fonts

The three built-in fonts are very nice. However, a designer, a manager, or a customer may want a different font. Or perhaps you want to use a font for specialized purposes, such as a dingbats font instead of a series of PNG graphics. The easiest way to accomplish this is to package the desired font(s) with your application. To do this, simply create an assets/ folder in the project root, and put your TrueType (TTF) fonts in that folder. You might, for example, create assets/fonts/ and put your TTF files in there.

Then, you need to tell your widgets to use that font. Unfortunately, you can no longer use layout XML for this, since the XML does not know about any fonts you may have tucked away as an application asset. Instead, you need to make the change in Java code:

importandroid.widget.TextView;
importjava.io.File;

public class FontSampler extends Activity {
  @Override
  public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);

    TextViewtv=(TextView)findViewById(R.id.custom);
    Typeface face=Typeface.createFromAsset(getAssets(),
                                          "fonts/HandmadeTypewriter.ttf");

    tv.setTypeface(face);

    File font=new File(Environment.getExternalStorageDirectory(),
                     "MgOpenCosmeticaBold.ttf");

    if (font.exists()) {
      tv=(TextView)findViewById(R.id.file);
      face=Typeface.createFromFile(font);

      tv.setTypeface(face);
    }
    else {
      findViewById(R.id.filerow).setVisibility(View.GONE);
    }
  }
}

Here, we grab the TextView for our custom sample, and then create a Typeface object via the static createFromAsset() builder method. This takes the application's AssetManager (from getAssets()) and a path within your assets/ directory to the font you want.

Then, it is just a matter of telling the TextView to setTypeface(), providing the Typeface we just created. In this case, we are using the Handmade Typewriter font. You can also load a font out of a local file and use it. The benefit is that you can customize your fonts after your application has been distributed. On the other hand, you have to somehow arrange to get the font onto the device. But, just as you can get a Typeface via createFromAsset(), you can get a Typeface via createFromFile(). In our FontSampler, we look in the root of “external storage” (typically the SD card) for the MgOpenCosmeticaBold TrueType font file, and if it is found, we use it for the fifth row of the table. Otherwise, we hide that row.

Figure 42–1 shows the results.

images

Figure 42–1. The FontSampler application

We will go into more details regarding assets and local files in an upcoming chapter.

Note that Android does not seem to like all TrueType fonts. When Android dislikes a custom font, rather than raise an Exception, it seems to substitute Droid Sans ("sans") quietly. So, if you try to use a different font and it does not appear to be working, it might be incompatible with Android, for whatever reason.

Here a Glyph, There a Glyph

TrueType fonts can be rather pudgy, particularly if they support an extensive subset of the available Unicode characters. The Handmade Typewriter font used in the previous section runs over 70KB; the DejaVu free fonts can run upwards of 500KB apiece. Even compressed, these add bulk to your application, so be careful not to go overboard with custom fonts, lest your application take up too much room on your users' phones.

Conversely, bear in mind that fonts may not have all of the glyphs that you need. As an example, let's talk about the ellipsis.

Android's TextView class has the built-in ability to “ellipsize” text, truncating it and adding an ellipsis if the text is longer than the available space. You can use this via the android:ellipsize attribute, for example. This works fairly well, at least for single-line text.

The ellipsis that Android uses is not three periods. Rather, it uses an actual ellipsis character, where the three dots are contained in a single glyph. Hence, any font that you use for which you also use the “ellipsizing” feature will need the ellipsis glyph.

Beyond that, though, Android pads out the string that gets rendered on the screen, such that the length (in characters) is the same before and after ellipsizing. To make this work, Android replaces one character with the ellipsis, and replaces all other removed characters with the Unicode character ZERO WIDTH NO-BREAK SPACE (U+FEFF). As a result, the extra characters after the ellipsis do not take up any visible space onscreen, yet they can be part of the string. However, this means any custom fonts you use for TextView widgets that you use with android:ellipsize must also support this special Unicode character. Not all fonts do, and you will get artifacts in the onscreen representation of your shortened strings if your font lacks this character (e.g., rogue Xs appear at the end of the line). Another side-effect of this approach is that it can be dicey to predict whether any string length arithmetic, such as a simple length() Java call, will return the value you expect. It's almost counter-intuitive, but Android is trying to present you with a consistent answer, whereas your previous experience with Java and fonts might have conditioned you to expect variable results.

And, of course, Android's international deployment means your font must handle any language your users might be looking to enter, perhaps through a language-specific input method editor.

Hence, while using custom fonts in Android is very possible, there are many potential problems, and so you must weigh carefully the benefits of the custom fonts versus their potential costs.

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

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