Is it possible to set a custom font for entire of application? Is it possible to set a custom font for entire of application? android android

Is it possible to set a custom font for entire of application?


Yes with reflection. This works (based on this answer):

(Note: this is a workaround due to lack of support for custom fonts, so if you want to change this situation please do star to up-vote the android issue here). Note: Do not leave "me too" comments on that issue, everyone who has stared it gets an email when you do that. So just "star" it please.

import java.lang.reflect.Field;import android.content.Context;import android.graphics.Typeface;public final class FontsOverride {    public static void setDefaultFont(Context context,            String staticTypefaceFieldName, String fontAssetName) {        final Typeface regular = Typeface.createFromAsset(context.getAssets(),                fontAssetName);        replaceFont(staticTypefaceFieldName, regular);    }    protected static void replaceFont(String staticTypefaceFieldName,            final Typeface newTypeface) {        try {            final Field staticField = Typeface.class                    .getDeclaredField(staticTypefaceFieldName);            staticField.setAccessible(true);            staticField.set(null, newTypeface);        } catch (NoSuchFieldException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }    }}

You then need to overload the few default fonts, for example in an application class:

public final class Application extends android.app.Application {    @Override    public void onCreate() {        super.onCreate();        FontsOverride.setDefaultFont(this, "DEFAULT", "MyFontAsset.ttf");        FontsOverride.setDefaultFont(this, "MONOSPACE", "MyFontAsset2.ttf");        FontsOverride.setDefaultFont(this, "SERIF", "MyFontAsset3.ttf");        FontsOverride.setDefaultFont(this, "SANS_SERIF", "MyFontAsset4.ttf");    }}

Or course if you are using the same font file, you can improve on this to load it just once.

However I tend to just override one, say "MONOSPACE", then set up a style to force that font typeface application wide:

<resources>    <style name="AppBaseTheme" parent="android:Theme.Light">    </style>    <!-- Application theme. -->    <style name="AppTheme" parent="AppBaseTheme">        <item name="android:typeface">monospace</item>    </style></resources>

API 21 Android 5.0

I've investigated the reports in the comments that it doesn't work and it appears to be incompatible with the theme android:Theme.Material.Light.

If that theme is not important to you, use an older theme, e.g.:

<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">    <item name="android:typeface">monospace</item></style>


There is a great library for custom fonts in android:Calligraphy

here is a sample how to use it.

in Gradle you need to put this line into your app's build.gradle file:

dependencies {    compile 'uk.co.chrisjenx:calligraphy:2.2.0'}

and then make a class that extends Application and write this code:

public class App extends Application {    @Override    public void onCreate() {        super.onCreate();        CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()                        .setDefaultFontPath("your font path")                        .setFontAttrId(R.attr.fontPath)                        .build()        );    }} 

and in the activity class put this method before onCreate:

@Overrideprotected void attachBaseContext(Context newBase) {    super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));}

and the last thing your manifest file should look like this:

<application   .   .   .   android:name=".App">

and it will change the whole activity to your font! it's simple and clean!


While this would not work for an entire application, it would work for an Activity and could be re-used for any other Activity. I've updated my code thanks to @FR073N to support other Views. I'm not sure about issues with Buttons, RadioGroups, etc. because those classes all extend TextView so they should work just fine. I added a boolean conditional for using reflection because it seems very hackish and might notably compromise performance.

Note: as pointed out, this will not work for dynamic content! For that, it's possible to call this method with say an onCreateView or getView method, but requires additional effort.

/** * Recursively sets a {@link Typeface} to all * {@link TextView}s in a {@link ViewGroup}. */public static final void setAppFont(ViewGroup mContainer, Typeface mFont, boolean reflect){    if (mContainer == null || mFont == null) return;    final int mCount = mContainer.getChildCount();    // Loop through all of the children.    for (int i = 0; i < mCount; ++i)    {        final View mChild = mContainer.getChildAt(i);        if (mChild instanceof TextView)        {            // Set the font if it is a TextView.            ((TextView) mChild).setTypeface(mFont);        }        else if (mChild instanceof ViewGroup)        {            // Recursively attempt another ViewGroup.            setAppFont((ViewGroup) mChild, mFont);        }        else if (reflect)        {            try {                Method mSetTypeface = mChild.getClass().getMethod("setTypeface", Typeface.class);                mSetTypeface.invoke(mChild, mFont);             } catch (Exception e) { /* Do something... */ }        }    }}

Then to use it you would do something like this:

final Typeface mFont = Typeface.createFromAsset(getAssets(),"fonts/MyFont.ttf"); final ViewGroup mContainer = (ViewGroup) findViewById(android.R.id.content).getRootView();HomeActivity.setAppFont(mContainer, mFont);

Hope that helps.