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 TextView
s, EditText
s, and Button
s.
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 ViewGroup
s as composite elements and View
s 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 Typeface
s on any TextView
s, EditText
s, and Button
s 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 ListView
s. 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.
Written by Matt
Related protips
7 Responses
i think Creating a class extending Textview and set an static Typeface at onDraw method is much better
That work great , thank you
Thanks for great work
Thanks.. Its working great. You save my time !!
Am I right to assume that, this works but only within the app not all over the handset ?
Thanks for tutorial but how to change font in PreferenceActivity?
Thanks for great work