How to change fontFamily of TextView in Android

941,572

Solution 1

From android 4.1 / 4.2 / 5.0, the following Roboto font families are available:

android:fontFamily="sans-serif"           // roboto regular
android:fontFamily="sans-serif-light"     // roboto light
android:fontFamily="sans-serif-condensed" // roboto condensed
android:fontFamily="sans-serif-black"     // roboto black
android:fontFamily="sans-serif-thin"      // roboto thin (android 4.2)
android:fontFamily="sans-serif-medium"    // roboto medium (android 5.0)

enter image description here

in combination with

android:textStyle="normal|bold|italic"

this 16 variants are possible:

  • Roboto regular
  • Roboto italic
  • Roboto bold
  • Roboto bold italic
  • Roboto-Light
  • Roboto-Light italic
  • Roboto-Thin
  • Roboto-Thin italic
  • Roboto-Condensed
  • Roboto-Condensed italic
  • Roboto-Condensed bold
  • Roboto-Condensed bold italic
  • Roboto-Black
  • Roboto-Black italic
  • Roboto-Medium
  • Roboto-Medium italic

fonts.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="font_family_light">sans-serif-light</string>
    <string name="font_family_medium">sans-serif-medium</string>
    <string name="font_family_regular">sans-serif</string>
    <string name="font_family_condensed">sans-serif-condensed</string>
    <string name="font_family_black">sans-serif-black</string>
    <string name="font_family_thin">sans-serif-thin</string>
</resources>

Solution 2

Starting from Android-Studio 3.0 its very easy to change font family

Using support library 26, it will work on devices running Android API version 16 and higher

Create a folder font under res directory .Download the font which ever you want and paste it inside font folder. The structure should be some thing like below

Here

Note: As of Android Support Library 26.0, you must declare both sets of attributes ( android: and app: ) to ensure your fonts load on devices running Api 26 or lower.

Now you can change font in layout using

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/dancing_script"
app:fontFamily="@font/dancing_script"/>

To change Programatically

 Typeface typeface = getResources().getFont(R.font.myfont);
   //or to support all versions use
Typeface typeface = ResourcesCompat.getFont(context, R.font.myfont);
 textView.setTypeface(typeface);  

To change font using styles.xml create a style

 <style name="Regular">
        <item name="android:fontFamily">@font/dancing_script</item>
        <item name="fontFamily">@font/dancing_script</item>
        <item name="android:textStyle">normal</item>
 </style>

and apply this style to TextView

  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    style="@style/Regular"/>

you can also Create your own font family

- Right-click the font folder and go to New > Font resource file. The New Resource File window appears.

- Enter the file name, and then click OK. The new font resource XML opens in the editor.

Write your own font family here , for example

<font-family xmlns:android="http://schemas.android.com/apk/res/android">
    <font
        android:fontStyle="normal"
        android:fontWeight="400"
        android:font="@font/lobster_regular" />
    <font
        android:fontStyle="italic"
        android:fontWeight="400"
        android:font="@font/lobster_italic" />
</font-family>

this is simply a mapping of a specific fontStyle and fontWeight to the font resource which will be used to render that specific variant. Valid values for fontStyle are normal or italic; and fontWeight conforms to the CSS font-weight specification

1. To change fontfamily in layout you can write

 <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:fontFamily="@font/lobster"/>

2. To Change Programmatically

 Typeface typeface = getResources().getFont(R.font.lobster);
   //or to support all versions use
Typeface typeface = ResourcesCompat.getFont(context, R.font.lobster);
 textView.setTypeface(typeface);  

To change font of entire App Add these two lines in AppTheme

 <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
     <item name="android:fontFamily">@font/your_font</item>
     <item name="fontFamily">@font/your_font</item>
  </style>

See the Documentation , Android Custom Fonts Tutorial For more info

Solution 3

This is the way to set the font programmatically:

TextView tv = (TextView) findViewById(R.id.appname);
Typeface face = Typeface.createFromAsset(getAssets(),
            "fonts/epimodem.ttf");
tv.setTypeface(face);

put the font file in your assets folder. In my case I created a subdirectory called fonts.

EDIT: If you wonder where is your assets folder see this question

Solution 4

I had to parse /system/etc/fonts.xml in a recent project. Here are the current font families as of Lollipop:

╔════╦════════════════════════════╦═════════════════════════════╗
║    ║ FONT FAMILY                ║ TTF FILE                    ║
╠════╬════════════════════════════╬═════════════════════════════╣
║  1 ║ casual                     ║ ComingSoon.ttf              ║
║  2 ║ cursive                    ║ DancingScript-Regular.ttf   ║
║  3 ║ monospace                  ║ DroidSansMono.ttf           ║
║  4 ║ sans-serif                 ║ Roboto-Regular.ttf          ║
║  5 ║ sans-serif-black           ║ Roboto-Black.ttf            ║
║  6 ║ sans-serif-condensed       ║ RobotoCondensed-Regular.ttf ║
║  7 ║ sans-serif-condensed-light ║ RobotoCondensed-Light.ttf   ║
║  8 ║ sans-serif-light           ║ Roboto-Light.ttf            ║
║  9 ║ sans-serif-medium          ║ Roboto-Medium.ttf           ║
║ 10 ║ sans-serif-smallcaps       ║ CarroisGothicSC-Regular.ttf ║
║ 11 ║ sans-serif-thin            ║ Roboto-Thin.ttf             ║
║ 12 ║ serif                      ║ NotoSerif-Regular.ttf       ║
║ 13 ║ serif-monospace            ║ CutiveMono.ttf              ║
╚════╩════════════════════════════╩═════════════════════════════╝

Here is the parser (based off FontListParser):

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.util.Xml;

/**
 * Helper class to get the current font families on an Android device.</p>
 * 
 * Usage:</p> {@code List<SystemFont> fonts = FontListParser.safelyGetSystemFonts();}</p>
 */
public final class FontListParser {

    private static final File FONTS_XML = new File("/system/etc/fonts.xml");

    private static final File SYSTEM_FONTS_XML = new File("/system/etc/system_fonts.xml");

    public static List<SystemFont> getSystemFonts() throws Exception {
        String fontsXml;
        if (FONTS_XML.exists()) {
            fontsXml = FONTS_XML.getAbsolutePath();
        } else if (SYSTEM_FONTS_XML.exists()) {
            fontsXml = SYSTEM_FONTS_XML.getAbsolutePath();
        } else {
            throw new RuntimeException("fonts.xml does not exist on this system");
        }
        Config parser = parse(new FileInputStream(fontsXml));
        List<SystemFont> fonts = new ArrayList<>();

        for (Family family : parser.families) {
            if (family.name != null) {
                Font font = null;
                for (Font f : family.fonts) {
                    font = f;
                    if (f.weight == 400) {
                        break;
                    }
                }
                SystemFont systemFont = new SystemFont(family.name, font.fontName);
                if (fonts.contains(systemFont)) {
                    continue;
                }
                fonts.add(new SystemFont(family.name, font.fontName));
            }
        }

        for (Alias alias : parser.aliases) {
            if (alias.name == null || alias.toName == null || alias.weight == 0) {
                continue;
            }
            for (Family family : parser.families) {
                if (family.name == null || !family.name.equals(alias.toName)) {
                    continue;
                }
                for (Font font : family.fonts) {
                    if (font.weight == alias.weight) {
                        fonts.add(new SystemFont(alias.name, font.fontName));
                        break;
                    }
                }
            }
        }

        if (fonts.isEmpty()) {
            throw new Exception("No system fonts found.");
        }

        Collections.sort(fonts, new Comparator<SystemFont>() {

            @Override
            public int compare(SystemFont font1, SystemFont font2) {
                return font1.name.compareToIgnoreCase(font2.name);
            }

        });

        return fonts;
    }

    public static List<SystemFont> safelyGetSystemFonts() {
        try {
            return getSystemFonts();
        } catch (Exception e) {
            String[][] defaultSystemFonts = {
                    {
                            "cursive", "DancingScript-Regular.ttf"
                    }, {
                            "monospace", "DroidSansMono.ttf"
                    }, {
                            "sans-serif", "Roboto-Regular.ttf"
                    }, {
                            "sans-serif-light", "Roboto-Light.ttf"
                    }, {
                            "sans-serif-medium", "Roboto-Medium.ttf"
                    }, {
                            "sans-serif-black", "Roboto-Black.ttf"
                    }, {
                            "sans-serif-condensed", "RobotoCondensed-Regular.ttf"
                    }, {
                            "sans-serif-thin", "Roboto-Thin.ttf"
                    }, {
                            "serif", "NotoSerif-Regular.ttf"
                    }
            };
            List<SystemFont> fonts = new ArrayList<>();
            for (String[] names : defaultSystemFonts) {
                File file = new File("/system/fonts", names[1]);
                if (file.exists()) {
                    fonts.add(new SystemFont(names[0], file.getAbsolutePath()));
                }
            }
            return fonts;
        }
    }

    /* Parse fallback list (no names) */
    public static Config parse(InputStream in) throws XmlPullParserException, IOException {
        try {
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(in, null);
            parser.nextTag();
            return readFamilies(parser);
        } finally {
            in.close();
        }
    }

    private static Alias readAlias(XmlPullParser parser) throws XmlPullParserException, IOException {
        Alias alias = new Alias();
        alias.name = parser.getAttributeValue(null, "name");
        alias.toName = parser.getAttributeValue(null, "to");
        String weightStr = parser.getAttributeValue(null, "weight");
        if (weightStr == null) {
            alias.weight = 0;
        } else {
            alias.weight = Integer.parseInt(weightStr);
        }
        skip(parser); // alias tag is empty, ignore any contents and consume end tag
        return alias;
    }

    private static Config readFamilies(XmlPullParser parser) throws XmlPullParserException,
            IOException {
        Config config = new Config();
        parser.require(XmlPullParser.START_TAG, null, "familyset");
        while (parser.next() != XmlPullParser.END_TAG) {
            if (parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }
            if (parser.getName().equals("family")) {
                config.families.add(readFamily(parser));
            } else if (parser.getName().equals("alias")) {
                config.aliases.add(readAlias(parser));
            } else {
                skip(parser);
            }
        }
        return config;
    }

    private static Family readFamily(XmlPullParser parser) throws XmlPullParserException,
            IOException {
        String name = parser.getAttributeValue(null, "name");
        String lang = parser.getAttributeValue(null, "lang");
        String variant = parser.getAttributeValue(null, "variant");
        List<Font> fonts = new ArrayList<Font>();
        while (parser.next() != XmlPullParser.END_TAG) {
            if (parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }
            String tag = parser.getName();
            if (tag.equals("font")) {
                String weightStr = parser.getAttributeValue(null, "weight");
                int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
                boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
                String filename = parser.nextText();
                String fullFilename = "/system/fonts/" + filename;
                fonts.add(new Font(fullFilename, weight, isItalic));
            } else {
                skip(parser);
            }
        }
        return new Family(name, fonts, lang, variant);
    }

    private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
        int depth = 1;
        while (depth > 0) {
            switch (parser.next()) {
            case XmlPullParser.START_TAG:
                depth++;
                break;
            case XmlPullParser.END_TAG:
                depth--;
                break;
            }
        }
    }

    private FontListParser() {

    }

    public static class Alias {

        public String name;

        public String toName;

        public int weight;
    }

    public static class Config {

        public List<Alias> aliases;

        public List<Family> families;

        Config() {
            families = new ArrayList<Family>();
            aliases = new ArrayList<Alias>();
        }

    }

    public static class Family {

        public List<Font> fonts;

        public String lang;

        public String name;

        public String variant;

        public Family(String name, List<Font> fonts, String lang, String variant) {
            this.name = name;
            this.fonts = fonts;
            this.lang = lang;
            this.variant = variant;
        }

    }

    public static class Font {

        public String fontName;

        public boolean isItalic;

        public int weight;

        Font(String fontName, int weight, boolean isItalic) {
            this.fontName = fontName;
            this.weight = weight;
            this.isItalic = isItalic;
        }

    }

    public static class SystemFont {

        public String name;

        public String path;

        public SystemFont(String name, String path) {
            this.name = name;
            this.path = path;
        }

    }
}

Feel free to use the above class in your project. For example, you could give your users a selection of font families and set the typeface based on their preference.

A small incomplete example:

final List<FontListParser.SystemFont> fonts = FontListParser.safelyGetSystemFonts();
String[] items = new String[fonts.size()];
for (int i = 0; i < fonts.size(); i++) {
    items[i] = fonts.get(i).name;
}

new AlertDialog.Builder(this).setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        FontListParser.SystemFont selectedFont = fonts.get(which);
        // TODO: do something with the font
        Toast.makeText(getApplicationContext(), selectedFont.path, Toast.LENGTH_LONG).show();
    }
}).show();

Solution 5

Android doesn't allow you to set custom fonts from the XML layout. Instead, you must bundle the specific font file in your app's assets folder, and set it programmatically. Something like:

TextView textView = (TextView) findViewById(<your TextView ID>);
Typeface typeFace = Typeface.createFromAsset(getAssets(), "<file name>");
textView.setTypeface(typeFace);

Note that you can only run this code after setContentView() has been called. Also, only some fonts are supported by Android, and should be in a .ttf (TrueType) or .otf (OpenType) format. Even then, some fonts may not work.

This is a font that definitely works on Android, and you can use this to confirm that your code is working in case your font file isn't supported by Android.

Android O Update: This is now possible with XML in Android O, based on Roger's comment.

Share:
941,572
Tarik
Author by

Tarik

I am a software engineer with interests in different technologies.

Updated on July 15, 2022

Comments

  • Tarik
    Tarik almost 2 years

    So I'd like to change the android:fontFamily in Android but I don't see any pre-defined fonts in Android. How do I select one of the pre-defined ones? I don't really need to define my own TypeFace but all I need is something different from what it shows right now.

    <TextView
        android:id="@+id/HeaderText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="52dp"
        android:gravity="center"
        android:text="CallerBlocker"
        android:textSize="40dp"
        android:fontFamily="Arial"
     />
    

    It seems what I did up there won't really work! BTW android:fontFamily="Arial" was a stupid attempt!

  • Sam Lu
    Sam Lu over 11 years
    Don't forget this: android:fontFamily="sans-serif-thin" // roboto thin
  • tbruyelle
    tbruyelle about 11 years
    I saw a variant called "black small caps" in the roboto specimen book, but I don't manage to use it. Using android:fontFamily="sans-serif-black-small-caps" doesnt work. Does someone know?
  • Monty
    Monty almost 11 years
    i am not able to find any of these font-family what have you typed here .i am not able to find "sans-serif" together.
  • Christopher Perry
    Christopher Perry over 10 years
    This is a nice list. Does anyone have a link to where this information comes from? It would be nice if Google had this in their documentation in an easy to find place, say for the documentation of android:fontFamily on TextView.
  • Christian García
    Christian García over 10 years
    Any clue of what's the source of this answer's information? I'd like to read further about it
  • Adam Mackler
    Adam Mackler over 10 years
    This would be great information for, oh I don't know, how about the TextView API Javadocs. Just sayin'. Apparently this is the only official reference.
  • Rad Haring
    Rad Haring over 10 years
    Is it accurate to say that fontFamily supercedes typeface? Are we now no longer able to use serif or monospace? I don't think typeface is formally deprecated, just ignored when fontFamily is also present.
  • Rad Haring
    Rad Haring over 10 years
    I don't think it is the same thing, but it does appear that we can't use both. It seems that there are now no less than three different attributes mapped to setTypeface(). Namely fontFamily, typeface and textStyle. But I can't for the life of me figure out how these are precisely combined to resolve a concrete Typeface instance. Has anyone figured this out? Google's documentation is less than helpful...
  • Charles Madere
    Charles Madere over 10 years
    While this does work, please note that this can create a memory leak. It can be fixed using this answer.
  • Simon
    Simon about 10 years
    I have updated this answer with details of where the source of this information comes from and how to get a definitive list of android:fontFamily values, even vendor ones, from your devices. Its just waiting on peer review.
  • Newtonx
    Newtonx about 10 years
    The definitive list of fonts can be found in system_fonts.xml as explained here
  • Sandra
    Sandra almost 10 years
    Just a quick quesrtion, if I use android:fontFamily in versions prior to (< 4.1) Jelly Bean, will it crash my app or just be ignored?
  • Jakob Eriksson
    Jakob Eriksson almost 10 years
    @Sandra it will be ignored, so it's safe to use
  • android developer
    android developer over 9 years
    Where can I find in the documentation about the available font-families ?
  • Sagar Devanga
    Sagar Devanga over 9 years
    @ScootrNova i get this error when i use your solution. Error : Font asset not found gothic.ttf
  • android developer
    android developer over 9 years
    "sans-serif" (roboto regular) is the default, right?
  • Ricardo
    Ricardo over 9 years
    How can I use roboto condensed light? Thanks
  • android developer
    android developer about 9 years
    @Ricardo Best way is to look at the source: android.googlesource.com/platform/frameworks/base/+/… and android.googlesource.com/platform/frameworks/base/+/master/d‌​ata/… , which means you want to use "sans-serif-condensed-light"
  • android developer
    android developer about 9 years
    Do you know perhaps which version of Android added which font?
  • Jared Rummler
    Jared Rummler about 9 years
    @androiddeveloper I don't. You could probably find out by viewing the changes here: github.com/android/platform_frameworks_base/blob/…
  • AZ_
    AZ_ about 9 years
    Where to declare them?
  • android developer
    android developer about 9 years
    @AZ_ Just like many resource files, you can put it in any XML file you wish, inside the "res/values/" folder . For example, put it in "res/values/fonts.xml" . And, to use it, do simply like this for example : android:fontFamily="string/fontFamily__roboto_regular"
  • AZ_
    AZ_ about 9 years
    Thanks, I am using this github.com/norbsoft/android-typeface-helper and it's really helpful
  • android developer
    android developer about 9 years
    ok, the library is probably for doing it programmatically. here it's for XML
  • Jelle Fresen
    Jelle Fresen almost 9 years
    What if you use sans-serif-thin on Android 4.1? Will it default to sans-serif-light, sans-serif, or DroidSans?
  • gor
    gor over 8 years
    since 5.0 you can, post an example in separate answer
  • Pritish Joshi
    Pritish Joshi over 8 years
    How to apply this to whole app? Right now in example you are applying it only on on textview
  • Milon
    Milon over 8 years
    To use Roboto API level 16 is required otherwise, you will get an error.
  • Demigod
    Demigod almost 8 years
    So I guess the only font I can't get (without using the RobotoTextView library) is condensed light? right?
  • KasparTr
    KasparTr almost 8 years
    How about Noto family? I cant find a way to make my app use Noto as default font family
  • Samuel
    Samuel over 7 years
    @JaredRummler, forgive my ignorance. Why/What is weight==400 ?
  • Jared Rummler
    Jared Rummler over 7 years
    @Samuel I haven't looked at this code in a while, but 400 font weight is used for "normal" or "regular" fonts. Example, Roboto-Regular has a weight of 400.
  • scorpiodawg
    scorpiodawg over 7 years
  • Morozov
    Morozov about 7 years
    yep, but for example i want to use it functionanl, but didn t want to implement all library;)
  • Jeppe Leth
    Jeppe Leth about 7 years
    You can check out this project, for checking font compatibility on TextViews and in WebViews on different platform versions github.com/JeppeLeth/android_font_compat_tester
  • Roger Huang
    Roger Huang about 7 years
    "Android doesn't allow you to set custom fonts from the XML layout." This has been changed in Android O, which allows you to create customized font family and apply them in XML: developer.android.com/preview/features/working-with-fonts.ht‌​ml
  • Tash Pemhiwa
    Tash Pemhiwa about 7 years
    NB: This currently only works in Android Studio 3.0 Preview. It did not work for me on Android Studio 2.3.3. Hope that saves someone some time!
  • Akshatha S R
    Akshatha S R almost 7 years
    sans-serif-medium is not available in my case
  • Paradox
    Paradox over 6 years
    How could you get the font from within a fragment since you can't just do getResources()? EDIT: This line at the end of your answer worked for me: Typeface typeface = ResourcesCompat.getFont(context, R.font.myfont);
  • Dominikus K.
    Dominikus K. over 6 years
    Sadly this still does not work with IntelliJ (though working like a charm on Android Studio 3.0+).
  • Damn Vegetables
    Damn Vegetables over 6 years
    Does this require root or something? I ran this code on the Android emulator (version 8.1), and when I called getSystemFonts(), I got an exception org.xmlpull.v1.XmlPullParserException: END_TAG expected (position:START_TAG (empty) <axis tag='wdth' stylevalue='100.0'>@219:51 in java.io.InputStreamReader@f001fb3)
  • Leonid Ustenko
    Leonid Ustenko about 6 years
    Somehow it made font look corrupted in my case, comparing to Caligtraphy. Also fontWeight doesn't do anything
  • Manohar
    Manohar about 6 years
    @LeoDroidcoder it does work , make sure you used both android:fontWeight and app:fontWeight
  • Leonid Ustenko
    Leonid Ustenko about 6 years
    I checked several times. There is no effect.
  • jungledev
    jungledev over 5 years
    Note that xmlns:app="http://schemas.android.com/apk/res-auto" must be included in your root element declaration to ensure it doesn't throw the error "Namespace 'app' not bound"
  • jungledev
    jungledev over 5 years
    Yes, but user Redman's answer above is still very much so a necessary part of the solution.
  • Anton Kizema
    Anton Kizema over 5 years
    Please, modify your answer - add android:fontFamily="sans-serif-bold" which corresponds to Roboto-bold. Thanks
  • Tsung Wu
    Tsung Wu over 5 years
    Well this is not working for CJK :( Any other ideas?
  • coolDude
    coolDude over 5 years
    Can anyone explain how each TTF file was mapped as the default for each font family? For example, for sans-serif, why is it that Roboto-Regular was the TTF file used? I see many files listed in this font family. Why was this particular one chosen over the others?
  • coolDude
    coolDude over 5 years
    Okay, I see that you used a weight of 400 as a threshold to determine the default font. Why 400 though?
  • Senthilvel S
    Senthilvel S almost 5 years
    This library isu used to change font of all views in entire application. This is not applicable for adapter views such as list view. For that we need to add code in each adapter specifically
  • Akanshi Srivastava
    Akanshi Srivastava over 4 years
    And also, android:fontFamily="casual"
  • Vadim Kotov
    Vadim Kotov over 4 years
    Better use ResourcesCompat.getFont method
  • EvOlaNdLuPiZ
    EvOlaNdLuPiZ over 4 years
    very nice, thank you for this. idk why others have more stars but yours is confirmed to work with material design text view, you must use app:fontFamily= however, everything else is the same.
  • superuser
    superuser about 4 years
    there's a link for a full view of Roboto: fonts.google.com/specimen/Roboto
  • Hilal
    Hilal about 4 years
    YOu saved my life, I had just created a folder named font and it did not work. Anyway I used your way and it worked.Thanks
  • mcy
    mcy over 3 years
    This answer should be way more top in 2020
  • Androidcoder
    Androidcoder about 3 years
    Right-click main, select 'New', select 'Android Resource File'. In popup window type 'font' for name, select 'Font' from drop-down 'Resource Type' list. Click 'OK'.
  • Sharan
    Sharan about 3 years
    @Manohar How to use it in conjunction with a Textvo