Last week, we looked at applying a custom font to an Android TextView. In this post, we'll look at a generalized approach, which is more complex, but also more suitable for a repeated use of custom fonts.
Custom Fonts on Android Series Overview
Applying a Custom Font to All TextViews
The solution we presented last week is excellent for a single (or very limited) use of custom fonts. However, if you're using it multiple times throughout your app, it is inefficient memory-wise (allocated the fontface many times) and code-wise (repeating the same code).
Providing the Font Memory-Efficient
The time of really weak Android phones is over, but we still should optimize for efficiency. Thus, we should cache our custom fonts. We like the solution from britzl on stackoverflow and adjusted it a bit to our taste:
public class FontCache {
private static HashMap<String, Typeface> fontCache = new HashMap<>();
public static Typeface getTypeface(String fontname, Context context) {
Typeface typeface = fontCache.get(fontname);
if (typeface == null) {
try {
typeface = Typeface.createFromAsset(context.getAssets(), fontname);
} catch (Exception e) {
return null;
}
fontCache.put(fontname, typeface);
}
return typeface;
}
}
Update December 2015: We've improved the code. Thank you, Alex Morozov, for your suggestion!
This caches the fonts while minimizing the number of accesses to the assets. Now, since we've a method to access our custom font, let's implement a class, which extends TextView.
Extending TextView
Next, we'll create a new Java class, which extends TextView. This allows us to use that class in all XML views. It inherits all functionality and properties of a regular TextView; but adds our custom font.
Once again, we're taking a peek at the source code of our eat foody project. The code might look complex for a second, but is straight-forward:
public class EatFoodyTextView extends TextView {
public EatFoodyTextView(Context context) {
super(context);
applyCustomFont(context);
}
public EatFoodyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
applyCustomFont(context);
}
public EatFoodyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
applyCustomFont(context);
}
private void applyCustomFont(Context context) {
Typeface customFont = FontCache.getTypeface("SourceSansPro-Regular.ttf", context);
setTypeface(customFont);
}
}
The first three methods are just constructors, which we override to call a single method applyCustomFont()
. That method is the important piece of the puzzle. It simply gets the (hopefully cached) font from our FontCache class. Lastly, we've to call setTypeface()
with the font and we're almost done. In case you're wondering, we can call the setTypeface()
directly (and not on a TextView object), since we're extending the TextView class.
Using the Class
You might wonder, if so much preparation is worth the effort. In this section you'll see that it is indeed. Because all you've left to do is use the class in an XML view and it automatically has your custom font. There is no Java code necessary!
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.futurestudio.foody.views.EatFoodyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/eat_foody_green_dark"
android:textSize="20sp"
android:text="Future Studio Blog"
android:layout_marginBottom="24dp"/>
</RelativeLayout>
As you can see, you can continue to use all niceties (e.g. textSize, textColor) of TextView. Now, just replace all <TextView/>
elements with the class we just created, for example <com.futurestudio.foody.views.EatFoodyTextView/>
and you applied your custom font everywhere!
Next Steps
For most use cases, this level of custom fonts on Android should be sufficient. Nevertheless, we'll take a deeper look in our next post when we apply font styles to our custom TextViews.
As always, you can find us on Twitter @futurestud_io.