345

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>
tomrozb
  • 25,773
  • 31
  • 101
  • 122
  • 2
    This might help you: http://stackoverflow.com/a/16883281/1329733 – Jacob R Sep 17 '15 at 10:51
  • 2
    You can now specify custom fonts right from the XML in android studio 3.0 https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml.html – Seven Oct 25 '17 at 21:00

16 Answers16

326

The answer is yes.

Global Roboto light for TextView and Button classes:

<style name="AppTheme" parent="AppBaseTheme">
    <item name="android:textViewStyle">@style/RobotoTextViewStyle</item>
    <item name="android:buttonStyle">@style/RobotoButtonStyle</item>
</style>

<style name="RobotoTextViewStyle" parent="android:Widget.TextView">
    <item name="android:fontFamily">sans-serif-light</item>
</style>

<style name="RobotoButtonStyle" parent="android:Widget.Holo.Button">
    <item name="android:fontFamily">sans-serif-light</item>
</style>

Just select the style you want from list themes.xml, then create your custom style based on the original one. At the end, apply the style as the theme of the application.

<application
    android:theme="@style/AppTheme" >
</application>

It will work only with built-in fonts like Roboto, but that was the question. For custom fonts (loaded from assets for example) this method will not work.

EDIT 08/13/15

If you're using AppCompat themes, remember to remove android: prefix. For example:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:textViewStyle">@style/RobotoTextViewStyle</item>
    <item name="buttonStyle">@style/RobotoButtonStyle</item>
</style>

Note the buttonStyle doesn't contain android: prefix, but textViewStyle must contain it.

Hussein El Feky
  • 6,627
  • 5
  • 44
  • 57
tomrozb
  • 25,773
  • 31
  • 101
  • 122
  • 5
    Where did you get the `sans-serif-light` value from? Is there a list of valid values for `fontFamily` somewhere? I've been looking through the docs, as well as the theme and style files in the Android source and can't find anything. – Christopher Perry Oct 30 '13 at 18:38
  • From this answer: http://stackoverflow.com/questions/12128331/how-to-change-fontfamily-of-textview-in-android EDIT: But now I see you have posted same comment there ;) – tomrozb Oct 30 '13 at 19:37
  • 36
    this is possible only for API level 16.. the name "android:fontFamily" exists only in level 16 or above.. is there a way to do that also for API 14 for example? – Lorenzo Barbagli Dec 27 '13 at 18:34
  • 3
    @LorenzoBarbagli, you can check [Calligraphy](https://github.com/chrisjenx/Calligraphy) – Brais Gabin Jun 02 '14 at 10:23
  • Hi tomrozb, do you need to add a style-element for each widget-type? – Brabbeldas May 20 '15 at 17:37
  • @Brabbeldas Yes, you have to change style of each UI element type (eg. TextView, Button) to apply a custom font – tomrozb May 20 '15 at 17:44
  • 11
    Well what do I do if I have a custom font? – Rohit Tigga May 24 '15 at 08:27
  • Is there any way to change font family for all elements (views)? – Gurgen Hakobyan Feb 29 '16 at 15:25
  • 2
    yes,, I also want to add custom font to the entire app. How can i do that ?. Do i need to override TextView and replace all the TextView as suggested in first answer – John Jun 22 '16 at 14:03
  • TextViewStyle is only available for Android 11+, and that is wayyyyyy too limiting to be used. Ref: https://developer.android.com/reference/androidx/autofill/inline/common/TextViewStyle – Henrik Erlandsson Oct 26 '22 at 08:13
206

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.

João Magalhães
  • 2,785
  • 2
  • 13
  • 17
  • 13
    When targeting API 26+, this should be the accepted method. When using _Support Library_, just remove the `android:` prefix – webo80 Sep 06 '17 at 14:19
  • 1
    @webo80 on this particular case it has backwards compatibility since I'm using Theme.AppCompat so there's no need to add the unprefixed version – João Magalhães Sep 06 '17 at 15:44
  • 3
    if you use the unprefixed version only, it's ok. The prefixed one just will be ignored on API <26 – webo80 Sep 07 '17 at 07:42
  • 2
    This doesn't set the font everywhere... e.g. if you have styles that derive from `Base.TextAppearance.AppCompat`, it's not used there. – User Apr 10 '18 at 08:21
  • 3
    @Ixx, how to override those styles too? – c0dehunter Jun 14 '18 at 09:24
  • do you know how to change it programmatically? – majov Jul 11 '18 at 15:10
  • 2
    Remember to also use AppCompatTextView when targeting api<26 – Codelicious Nov 12 '18 at 22:07
  • if you do this, then it appears that you can't change fontFamily in a textAppearance. So be careful with it. – harmanjd Aug 27 '19 at 19:46
  • What about built-in fonts? In my case, I'd like to use them instead of adding duplicates or another ones. Those methods only take more space... – AtomX Aug 21 '21 at 18:28
  • 1
    fontFamily (without android prefix) overrides all TextViews so hard, you cannot even override it with attributes or styles. Tested on 8.1.0. Using only android:fontFamily works as expected on 8.1.0. – Henrik Erlandsson Oct 26 '22 at 08:19
66

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.

Guy Luz
  • 3,372
  • 20
  • 43
34

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

longi
  • 11,104
  • 10
  • 55
  • 89
  • 32
    This is not the solution. I'm using many different views, not only the TextView. I want to set the font once and forget about it. In addition, your code creates new object for every TextView. At least declare the field as static to load the font from assets once. – tomrozb May 06 '13 at 20:17
  • 2
    ...well, there's a find and replace function, which works really well in this case – longi Sep 21 '15 at 09:06
  • 1
    This isn't going to work. You cannot call `getContext()` when the variable is static. You should implement it in singleton like way, otherwise the current code won't even compile. – tomrozb Oct 15 '15 at 15:15
  • 1
    i reverted the last commit. – longi Oct 19 '15 at 09:16
  • 1
    @tomrozb :D i just realized, that the last fast changes i did, were because of your comments! as you have enough points, you are welcome to optimize the code example yourself. otherwise we will still talk about the topic in a few years, when nobody cares about smartphones anymore ;) – longi Oct 21 '15 at 09:43
  • 1
    I just suggested to optimize the code (keep the typeface as static field, so it's not loaded from assets for every single custom view). I'm not using this answer because there are better options to load fonts globally. I'm not going to optimize it, because IMO it's the worst solution to apply custom font to a view. – tomrozb Oct 23 '15 at 08:11
  • IMO this was the only way which worked in API 14. but i understand your static point, so thanks for your comment, but it s a won't fix ;) – longi Oct 23 '15 at 08:30
  • how can we revert back to default. I am doing something like this: http://pastebin.com/qJqbEBqE – Shubham AgaRwal Feb 15 '16 at 15:53
  • The question is about changing all the views in app to particular font rather than customizing all views. – PranavKAndro Jul 08 '17 at 04:42
15

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..

nirazverma
  • 1,001
  • 10
  • 15
  • I tried this and it's working fine but I am wondering why people use the calligraphy library instead? – M.Muzammil Jul 27 '21 at 09:39
  • @M.Muzammil calligraphy is a pretty old library that's not even maintained anymore. generally people use it because they have used it for ages. when calligraphy was released, the solution described in this answer was not possible, because font resources were only introduced in 2017 – Adam Burley Sep 10 '21 at 15:54
8

It's very very very easy to do in Android Studio.

  1. In this method you need to verify your minsdkveriosn. It must need minsdkversion >=16

Ex:

  1. Create "font" folder inside "res" folder. In android studio New > Folder > Font Folder.

See image:

  1. Upload your font file to that font folder.

Ex:

  1. In you style.xml file, Under style in "Base application theme" add this line.

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

Ex:

General Grievance
  • 4,555
  • 31
  • 31
  • 45
7

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.

Allen Chan
  • 4,041
  • 2
  • 19
  • 16
5

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

Community
  • 1
  • 1
4

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.

Pang
  • 9,564
  • 146
  • 81
  • 122
moahmed ayed
  • 636
  • 7
  • 10
2

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");
    }
Irvan Dwi Pangga
  • 322
  • 4
  • 15
1

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.

Community
  • 1
  • 1
Phileo99
  • 5,581
  • 2
  • 46
  • 54
0

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) { }
    }
}
FonzTech
  • 408
  • 1
  • 5
  • 13
0

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

Eric
  • 16,397
  • 8
  • 68
  • 76
  • You sure that works? According to Android doc: "Must be one of the following constant values: normal, sans, serif, monospace". – tomrozb Nov 03 '16 at 18:38
  • 1
    Oh I see...you're right...i didn't understand the question after all :x I just wanted to have my whole app to use a monospace font (not custom) and I saw it working so I posted this here.........i think my answer could still be useful for others who want to do something similar....so I'll edit it and leave it here.....i am ok is it accumulates down votes. thanks for pointing that out – Eric Nov 03 '16 at 19:42
  • Hey @Dave Cruise, does it only work for monospace? I have only tested it for monospace...and nothing else....so I'm not sure...but according to the documentation, it should work for "normal", "sans" and "serif" too...i think typeface is more general than font, so we cant use it to set font of app to a specific font like "consolas" or something. – Eric Nov 24 '16 at 09:02
  • @Eric yea. i have no idea too. monospace work like a charm but no luck for normal, sans or serif. – Dave Cruise Nov 24 '16 at 09:03
-1

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" />
Sanny Nagveker
  • 418
  • 3
  • 7
-1

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);
}
Ollie
  • 23
  • 1
-7

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)

Community
  • 1
  • 1
Martin Marconcini
  • 26,875
  • 19
  • 106
  • 144
  • 41
    Completely disagree with your commentary. Setting a font globally should be trivial to do, not something that requires the kinds of workarounds needed. It's up to the developers/designers of the world to avoid the "Comic Sans" applications, not Google/Apple to enforce that. – LocalPCGuy Jan 21 '14 at 21:47
  • 4
    Consistency > Fancy design. – Martin Marconcini Jan 21 '14 at 23:02
  • 14
    However, consistence < functionality. We develop apps that display biblical Hebrew. All of the stock fonts found on Android devices (including the latest Android L fonts) do an abysmal job of rendering cantillation marks (and they do a mediocre job on vowel marks, for that matter, although they are getting better). We absolutely need to use a custom font throughout our app, and we've had to write way too much code simply to get all the requisite views using it. – Ted Hopp Sep 10 '14 at 04:26