Last Updated: May 21, 2022
·
40.15K
· swampmobile

Android: Use a custom font everywhere

Android does not provide a mechanism for using a custom font file (TTF, OTF, etc) in all areas of your app. Instead you must employ a strategy to set a custom Typeface on all TextViews, EditTexts, and Buttons.

This post covers a strategy that should handle your needs for common apps.

The View Crawler

Layouts (and sub-layouts) in Android are tree hierarchies comprised of ViewGroups as composite elements and Views as leaf nodes. This tree can be crawled by visiting child views in your favorite order (breadth first or depth first). When crawling this tree, one can replace all the Typefaces on any TextViews, EditTexts, and Buttons that are encountered.

Here is a simple recursive implementation of a view crawler that will replace the Typeface for any appropriate view in the hierarchy:

public class FontChangeCrawler
{
    private Typeface typeface;

    public FontChangeCrawler(Typeface typeface)
    {
        this.typeface = typeface;
    }

    public FontChangeCrawler(AssetManager assets, String assetsFontFileName)
    {
        typeface = Typeface.createFromAsset(assets, assetsFontFileName);
    }

    public void replaceFonts(ViewGroup viewTree)
    {
        View child;
        for(int i = 0; i < viewTree.getChildCount(); ++i)
        {
            child = viewTree.getChildAt(i);
            if(child instanceof ViewGroup)
            {
                // recursive call
                replaceFonts((ViewGroup)child);
            }
            else if(child instanceof TextView)
            {
                // base case
                ((TextView) child).setTypeface(typeface);
            }
        }
    }
}

Replace Entire Activity's Typeface

To replace the default font in every view within an Activity's layout, simply use the FontChangeCrawler from above, like so:

@Override
public void setContentView(View view)
{
    super.setContentView(view);

    FontChangeCrawler fontChanger = new FontChangeCrawler(getAssets(), "font.otf");
    fontChanger.replaceFonts((ViewGroup)this.findViewById(android.R.id.content));
}

If you are not familiar with android.R.id.content, it is the official ID given to the root View within an Activity's layout.

Consider placing the above logic in a BaseActivity class.

Replace Fragment's Typeface

You will need to apply the FontChangeCrawler to each Fragment as well. Consider placing this logic in a BaseFragment class.

@Override
public void onActivityCreated(Bundle savedInstanceState)
{
    super.onActivityCreated(savedInstanceState);

    FontChangeCrawler fontChanger = new FontChangeCrawler(getAssets(), "font.otf");
    fontChanger.replaceFonts((ViewGroup) this.getView());
}

Handle Adapters, etc.

Replacing Activity fonts goes a long way, but most of us also have a plethora of ListViews. The list items in a ListView are built within an adapter, not within an Activity. Therefore, you will also need to use the FontChangeCrawler in your adapters:

...
if(convertView == null)
{
    convertView = inflater.inflate(R.layout.listitem, null);
    fontChanger.replaceFonts((ViewGroup)convertView);
}
...

What's Not Handled?

I will leave handling the ActionBar as an exercise for the reader. Also, consider how you might handle widgets whose typeface you don't want to change.

7 Responses
Add your response

i think Creating a class extending Textview and set an static Typeface at onDraw method is much better

over 1 year ago ·

That work great , thank you

over 1 year ago ·

Thanks for great work

over 1 year ago ·

Thanks.. Its working great. You save my time !!

over 1 year ago ·

Am I right to assume that, this works but only within the app not all over the handset ?

over 1 year ago ·

Thanks for tutorial but how to change font in PreferenceActivity?

over 1 year ago ·

Thanks for great work

over 1 year ago ·