Software Development

Pro tip: Extend Android's TextView to use custom fonts

This quick guide on Android custom fonts covers how to implement them and common issues developers may run into when using them.

6_Android_logo.png

One thing that always bothered me about Android's TextView widget is that you couldn't specify a custom font in the XML layout. It's not a lot of work to load and apply a font in code, but after finding myself pounding out the same few lines of code on every project, I thought there had to be a better way.

As it turns out, extending TextView and adding a font name property is a breeze. Now I can copy a font into my project, set the name property in my layout, and let the custom class do its thing. In this tutorial, I teach you how to do the same. You can follow along with the step-by-step instructions or download and import the entire project directly into Eclipse.

1. Create a new Android project in Eclipse. Target API 14 (ICS) or better.

2. In the /assets directory (not the /resource directory), create a folder called /fonts. Copy your custom font here. You can use both TTF and OTF fonts. In my case, I included a font called pipe_dream.ttf.

3. In the /res/values folder, create a new file called attrs.xml. This is how the Android SDK lets you name custom properties for your widgets.

/res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyTextView">
<attr name="fontName" format="string" />
   	</declare-styleable>
</resources>

4. In /res/layouts, we will need to include our to-be-created custom text view in the activity_main.xml file.

/res/layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:customfontdemo="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" 
    android:gravity="center">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        android:padding="12dp"
        android:text="Standard Android Font" />
    
     <com.authorwjf.customfontdemo.MyTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="32sp"
        android:padding="12dp"
        customfontdemo:fontName="pipe_dream.ttf"
        android:text="Custom Android Font" />

</LinearLayout>

5. In the /src folder, we will want to create our MyTextView class. It extends the standard text view, plucks the font name from the custom attribute, and applies the type face.

/src/MyTextView.java
package com.authorwjf.customfontdemo;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;

public class MyTextView extends TextView {

	public MyTextView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(attrs);
	}
	
	public MyTextView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(attrs);
		
	}
	
	public MyTextView(Context context) {
		super(context);
		init(null);
	}
	
	private void init(AttributeSet attrs) {
		if (attrs!=null) {
			 TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MyTextView);
			 String fontName = a.getString(R.styleable.MyTextView_fontName);
			 if (fontName!=null) {
				 Typeface myTypeface = Typeface.createFromAsset(getContext().getAssets(), "fonts/"+fontName);
				 setTypeface(myTypeface);
			 }
			 a.recycle();
		}
	}

}

6. Because the text view is now self-contained, we aren't required to make any modifications to our /src/MainAcitivity.java file.

/src/MainActivity.java
package com.authorwjf.customfontdemo;

import android.os.Bundle;
import android.app.Activity;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}

}

The application is ready to deploy (Figure A).

Figure A

androidcustomfont042314.png

Despite the simplicity of working with custom fonts, keep in mind the following points, which are based on my observations.

  • Your fonts must live in the asset folder, not the resource folder.
  • I have read documentation claiming OTF fonts are not supported; however, I have had no issues with them.
  • The framework uses the file name of the font, not the font's internal name property.
  • The font extension (ttf or otf) needs to be lower case.
  • I have run across fonts that simply don't seem to work despite installing and working fine on my Mac and PC. So if you feel like you are doing everything right and you still aren't seeing your custom font, try another font file just to be sure it's your code and not the framework/font that is the problem.

About

William J Francis began programming computers at age eleven. Specializing in embedded and mobile platforms, he has more than 20 years of professional software engineering under his belt, including a four year stint in the US Army's Military Intellige...

2 comments
Rahulrn
Rahulrn

Have you tried with layerType=hardware? With ART runtime I see issues with text rendering.

jayala08
jayala08

Really useful, thanks a lot.