[android] How to set default font family for entire Android app

I'm using the Roboto light font in my app. To set the font I've to add the android:fontFamily="sans-serif-light" to every view. Is there any way to declare the Roboto font as default font family to entire app? I've tried like this but it didn't seem to work.

<style name="AppBaseTheme" parent="android:Theme.Light"></style>

<style name="AppTheme" parent="AppBaseTheme">
    <item name="android:fontFamily">sans-serif-light</item>
</style>

This question is related to android android-fonts

The answer is


This is how we do it:

private static void OverrideDefaultFont(string defaultFontNameToOverride, string customFontFileNameInAssets, AssetManager assets)
{
    //Load custom Font from File                
    Typeface customFontTypeface = Typeface.CreateFromAsset(assets, customFontFileNameInAssets);

    //Get Fontface.Default Field by reflection
    Class typeFaceClass = Class.ForName("android.graphics.Typeface");
    Field defaultFontTypefaceField = typeFaceClass.GetField(defaultFontNameToOverride);

    defaultFontTypefaceField.Accessible = true;
    defaultFontTypefaceField.Set(null, customFontTypeface);
}

This is work for my project, source https://gist.github.com/artem-zinnatullin/7749076

Create fonts directory inside Asset Folder and then copy your custom font to fonts directory, example I am using trebuchet.ttf;

Create a class TypefaceUtil.java;

import android.content.Context;
import android.graphics.Typeface;
import android.util.Log;

import java.lang.reflect.Field;
public class TypefaceUtil {

    public static void overrideFont(Context context, String defaultFontNameToOverride, String customFontFileNameInAssets) {
        try {
            final Typeface customFontTypeface = Typeface.createFromAsset(context.getAssets(), customFontFileNameInAssets);

            final Field defaultFontTypefaceField = Typeface.class.getDeclaredField(defaultFontNameToOverride);
            defaultFontTypefaceField.setAccessible(true);
            defaultFontTypefaceField.set(null, customFontTypeface);
        } catch (Exception e) {

        }
    }
}

Edit theme in styles.xml add below

<item name="android:typeface">serif</item>

Example in My styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:typeface">serif</item><!-- Add here -->
    </style>


    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        <item name="android:windowActionBarOverlay">true</item>
        <item name="android:windowFullscreen">true</item>
    </style>
</resources>

Finally, in Activity or Fragment onCreate call TypefaceUtil.java

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TypefaceUtil.overrideFont(getContext(), "SERIF", "fonts/trebuchet.ttf");
    }

Another way to do this for the whole app is using reflection based on this answer

public class TypefaceUtil {
    /**
     * Using reflection to override default typefaces
     * NOTICE: DO NOT FORGET TO SET TYPEFACE FOR APP THEME AS DEFAULT TYPEFACE WHICH WILL BE
     * OVERRIDDEN
     *
     * @param typefaces map of fonts to replace
     */
    public static void overrideFonts(Map<String, Typeface> typefaces) {
        try {
            final Field field = Typeface.class.getDeclaredField("sSystemFontMap");
            field.setAccessible(true);
            Map<String, Typeface> oldFonts = (Map<String, Typeface>) field.get(null);
            if (oldFonts != null) {
                oldFonts.putAll(typefaces);
            } else {
                oldFonts = typefaces;
            }
            field.set(null, oldFonts);
            field.setAccessible(false);
        } catch (Exception e) {
            Log.e("TypefaceUtil", "Can not set custom fonts");
        }
    }

    public static Typeface getTypeface(int fontType, Context context) {
        // here you can load the Typeface from asset or use default ones
        switch (fontType) {
            case BOLD:
                return Typeface.create(SANS_SERIF, Typeface.BOLD);
            case ITALIC:
                return Typeface.create(SANS_SERIF, Typeface.ITALIC);
            case BOLD_ITALIC:
                return Typeface.create(SANS_SERIF, Typeface.BOLD_ITALIC);
            case LIGHT:
                return Typeface.create(SANS_SERIF_LIGHT, Typeface.NORMAL);
            case CONDENSED:
                return Typeface.create(SANS_SERIF_CONDENSED, Typeface.NORMAL);
            case THIN:
                return Typeface.create(SANS_SERIF_MEDIUM, Typeface.NORMAL);
            case MEDIUM:
                return Typeface.create(SANS_SERIF_THIN, Typeface.NORMAL);
            case REGULAR:
            default:
                return Typeface.create(SANS_SERIF, Typeface.NORMAL);
        }
    }
}

then whenever you want to override the fonts you can just call the method and give it a map of typefaces as follows:

Typeface regular = TypefaceUtil.getTypeface(REGULAR, context);
Typeface light = TypefaceUtil.getTypeface(REGULAR, context);
Typeface condensed = TypefaceUtil.getTypeface(CONDENSED, context);
Typeface thin = TypefaceUtil.getTypeface(THIN, context);
Typeface medium = TypefaceUtil.getTypeface(MEDIUM, context);
Map<String, Typeface> fonts = new HashMap<>();
fonts.put("sans-serif", regular);
fonts.put("sans-serif-light", light);
fonts.put("sans-serif-condensed", condensed);
fonts.put("sans-serif-thin", thin);
fonts.put("sans-serif-medium", medium);
TypefaceUtil.overrideFonts(fonts);

for full example check

This only works for Android SDK 21 and above for earlier versions check the full example


I know this question is quite old, but I have found a nice solution. Basically, you pass a container layout to this function, and it will apply the font to all supported views, and recursively cicle in child layouts:

public static void setFont(ViewGroup layout)
{
    final int childcount = layout.getChildCount();
    for (int i = 0; i < childcount; i++)
    {
        // Get the view
        View v = layout.getChildAt(i);

        // Apply the font to a possible TextView
        try {
            ((TextView) v).setTypeface(MY_CUSTOM_FONT);
            continue;
        }
        catch (Exception e) { }

        // Apply the font to a possible EditText
        try {
            ((TextView) v).setTypeface(MY_CUSTOM_FONT);
            continue;
        }
        catch (Exception e) { }

        // Recursively cicle into a possible child layout
        try {
            ViewGroup vg = (ViewGroup) v;
            Utility.setFont(vg);
            continue;
        }
        catch (Exception e) { }
    }
}

READ UPDATES BELOW

I had the same issue with embedding a new font and finally got it to work with extending the TextView and set the typefont inside.

public class YourTextView extends TextView {

    public YourTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public YourTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public YourTextView(Context context) {
        super(context);
        init();
    }

    private void init() {
        Typeface tf = Typeface.createFromAsset(context.getAssets(),
            "fonts/helveticaneue.ttf");
        setTypeface(tf);
    }
}

You have to change the TextView Elements later to from to in every element. And if you use the UI-Creator in Eclipse, sometimes he doesn't show the TextViews right. Was the only thing which work for me...

UPDATE

Nowadays I'm using reflection to change typefaces in whole application without extending TextViews. Check out this SO post

UPDATE 2

Starting with API Level 26 and available in 'support library' you can use

android:fontFamily="@font/embeddedfont"

Further information: Fonts in XML


To change your app font follow the following steps:

  1. Inside res directory create a new directory and name it font.
  2. Insert your font .ttf/.otf inside the font folder, Make sure the font name is lower case letters and underscore only.
  3. Inside res -> values -> styles.xml inside <resources> -> <style> add your font <item name="android:fontFamily">@font/font_name</item>.

enter image description here

Now all your app text should be in the font that you add.


Add this line of code in your res/value/styles.xml

<item name="android:fontFamily">@font/circular_medium</item>

the entire style will look like that

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:fontFamily">@font/circular_medium</item>
</style>

change "circular_medium" to your own font name..


Try this library, its lightweight and easy to implement

https://github.com/sunnag7/FontStyler

<com.sunnag.fontstyler.FontStylerView
              android:textStyle="bold"
              android:text="@string/about_us"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:paddingTop="8dp"
              app:fontName="Lato-Bold"
              android:textSize="18sp"
              android:id="@+id/textView64" />

Android does not provide much in the way of support for applying fonts across the whole app (see this issue). You have 4 options to set the font for the entire app:

  • Option1: Apply reflection to change the system font
  • Option2: Create and subclass custom View classes for each View that needs a custom font
  • Option3: Implement a View Crawler which traverses the view hierarchy for the current screen
  • Option4: Use a 3rd party library.

Details of these options can be found here.


to merely set typeface of app to normal, sans, serif or monospace(not to a custom font!), you can do this.

define a theme and set the android:typeface attribute to the typeface you want to use in styles.xml:

<resources>

    <!-- custom normal activity theme -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <!-- other elements -->
        <item name="android:typeface">monospace</item>
    </style>

</resources>

apply the theme to the whole app in the AndroidManifest.xml file:

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application
        android:theme="@style/AppTheme" >
    </application>
</manifest>

android reference


The answer is no, you can't. See Is it possible to set a custom font for entire of application? for more information.

There are workarounds, but nothing in the lines of "one single line of code here and all my fonts will be this instead of that".

(I kind of thank Google -and Apple- for that). Custom fonts have a place, but making them easy to replace app wide, would have created an entire world of Comic Sans applications)


Not talk about performance, for custom font you can have a recursive method loop through all the views and set typeface if it's a TextView:

public class Font {
    public static void setAllTextView(ViewGroup parent) {
        for (int i = parent.getChildCount() - 1; i >= 0; i--) {
            final View child = parent.getChildAt(i);
            if (child instanceof ViewGroup) {
                setAllTextView((ViewGroup) child);
            } else if (child instanceof TextView) {
                ((TextView) child).setTypeface(getFont());
            }
        }
    }

    public static Typeface getFont() {
        return Typeface.createFromAsset(YourApplicationContext.getInstance().getAssets(), "fonts/whateverfont.ttf");
    }
}

In all your activity, pass current ViewGroup to it after setContentView and it's done:

ViewGroup group = (ViewGroup) getWindow().getDecorView().findViewById(android.R.id.content);
Font.setAllTextView(group);

For fragment you can do something similar.


Just use this lib compile it in your grade file

complie'me.anwarshahriar:calligrapher:1.0'

and use it in the onCreate method in the main activity

Calligrapher calligrapher = new Calligrapher(this);
calligrapher.setFont(this, "yourCustomFontHere.ttf", true);

This is the most elegant super fast way to do that.


With the release of Android Oreo you can use the support library to reach this goal.

  1. Check in your app build.gradle if you have the support library >= 26.0.0
  2. Add "font" folder to your resources folder and add your fonts there
  3. Reference your default font family in your app main style:

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
       <item name="android:fontFamily">@font/your_font</item>
       <item name="fontFamily">@font/your_font</item> <!-- target android sdk versions < 26 and > 14 if theme other than AppCompat -->
    </style>
    

Check https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml.html for more detailed information.