I'm trying to define a GUI layout using XML files in Android. As far as I can find out, there is no way to specify that your widgets should use a custom font (e.g. one you've placed in assets/font/) in XML files and you can only use the system installed fonts.

I know that, in the Java code, I could change the font of each widget manually using unique IDs. Alternatively, I could iterate over all the widgets in Java to make this change, but this would probably be very slow.

What other options do I have? Is there any better ways to making widgets that have a custom look? I don't particularly want to have to manually change the font for every new widget I add.

66 upvote
  flag
DrDefrost - please accept some answers, you'll get more responses on this site. – SK9
1 upvote
  flag
Here's one more similar question : //allinonescript.com/questions/9030204/… – Vins
upvote
  flag
Updated 05/2017: "The Support Library 26.0 Beta provides support to the Fonts in XML feature on devices running Android API version 14 and higher." See: developer.android.com/preview/features/… – albert c braun

16 Answers 11

The only way to use custom fonts is through the source code.

Just remember that Android runs on devices with very limited resources and fonts might require a good amount of RAM. The built-in Droid fonts are specially made and, if you note, have many characters and decorations missing.

upvote
  flag
"Just remember that Android runs on devices with very limited resources" --> this is becoming less and less the case. Quad core phone? Really?? – Sandy
9 upvote
  flag
I'd do more to show consideration of the context of tareqHs's answer, which predates your comment by a good 2 and a half years. – SK9
upvote
  flag
The first part of your response may have been true when you wrote your answer in 2010. The latter is superfluoys and beside the point: Droid was bad, ditched by Google in 2012 in favour of Roboto. The lack of choice in typography in Android is a flaw, not a feature; iOS has had multiple fonts available to developers since 2008 under primitive devices by today's standards. – cosmix
upvote
  flag
This answer is no longer valid. – Martin Konecny

Extend TextView and give it a custom attribute or just use the android:tag attribute to pass in a String of what font you want to use. You will need to pick a convention and stick to it such as I will put all of my fonts in the res/assets/fonts/ folder so your TextView class knows where to find them. Then in your constructor you just set the font manually after the super call.

1 upvote
  flag
See peter's answer for a fully coded example. – Intrications

You can't extend TextView to create a widget or use one in a widgets layout: http://developer.android.com/guide/topics/appwidgets/index.html

4 upvote
  flag
I suppose you can. – Vaibhav Mishra
1 upvote
  flag
Aha - the famous double use of the word "widget" strikes again! – Carl Whalley

You can extend TextView to set custom fonts as I learned here.

TextViewPlus.java:

package com.example;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

public class TextViewPlus extends TextView {
    private static final String TAG = "TextView";

    public TextViewPlus(Context context) {
        super(context);
    }

    public TextViewPlus(Context context, AttributeSet attrs) {
        super(context, attrs);
        setCustomFont(context, attrs);
    }

    public TextViewPlus(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setCustomFont(context, attrs);
    }

    private void setCustomFont(Context ctx, AttributeSet attrs) {
        TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.TextViewPlus);
        String customFont = a.getString(R.styleable.TextViewPlus_customFont);
        setCustomFont(ctx, customFont);
        a.recycle();
    }

    public boolean setCustomFont(Context ctx, String asset) {
        Typeface tf = null;
        try {
        tf = Typeface.createFromAsset(ctx.getAssets(), asset);  
        } catch (Exception e) {
            Log.e(TAG, "Could not get typeface: "+e.getMessage());
            return false;
        }

        setTypeface(tf);  
        return true;
    }

}

attrs.xml: (in res/values)

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="TextViewPlus">
        <attr name="customFont" format="string"/>
    </declare-styleable>
</resources>

main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:foo="http://schemas.android.com/apk/res/com.example"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <com.example.TextViewPlus
        android:id="@+id/textViewPlus1"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:text="@string/showingOffTheNewTypeface"
        foo:customFont="saxmono.ttf">
    </com.example.TextViewPlus>
</LinearLayout>

You would put "saxmono.ttf" in the assets folder.

UPDATE 8/1/13

There are serious memory concerns with this method. See chedabob's comment below.

upvote
  flag
Excellent. Thanks for the code. – Intrications
5 upvote
  flag
That looks nice, however, I'm getting an error when I try to use the "TextViewPlus" in the main.xml. I get the following: - error: Error parsing XML: unbound prefix - The prefix "foo" for attribute "foo:customFont" associated with an element type "supportLibs.TextViewPlus" is not bound. – Majjoodi
76 upvote
  flag
One thing to note is that this will generate dozens and dozens of TypeFace objects and eat up memory. There is a bug in pre-4.0 Android that doesn't free up TypeFaces properly. The easiest thing to do is create a TypeFace cache with a HashMap. This brought memory usage in my app down from 120+ mb to 18mb. code.google.com/p/android/issues/detail?id=9904 – chedabob
7 upvote
  flag
@Majjoodi: That typically happens if you forget to add the 2nd namespace to your layout: xmlns:foo="http://schemas.android.com/apk/res/com.example – Theo
11 upvote
  flag
VERY IMPORTANT - I would just like to double stress chedabob's advice. Unless you follow it, you will have a memory leak in pre-ICS. There are few solutions, one of them is in the link provided by chedabob, another one is here: //allinonescript.com/questions/8057010/listview-memory-leak. peter - please update your answer - it's great but not complete – Michał K
1 upvote
  flag
How do I set this custom attribute in styles.xml in addition to other textview attributes such as width and height? – loeschg
1 upvote
  flag
Is there a way to use foo:customFont in styles.xml? – Tom Fobear
1 upvote
  flag
@TomFobear There certainly is! You could take a look at my presentation and sample code that I presented at mdevcon, Droidcon, Dev Days and MobDevCon. Not only does it answer your question precisely, but it is a general tutorial about how to create custom views. – Paul Lammertsma
upvote
  flag
Similar example here in details Applying custom Font using Layouts – Sameer
upvote
  flag
What about the font of the actionbar? it's layout is hidden. – AlikElzin-kilaka
upvote
  flag
Also, isn't there a way to just define it as part of the theme, instead of manually defining it for every textview? – AlikElzin-kilaka
upvote
  flag
@chedabob That's what TypefaceTextView does, you can check out my answer on that. – Ragunath Jawahar
upvote
  flag
what about the memory problem now ?!! still on action ?!! – Muhammed Refaat
upvote
  flag
I made a library for that. github.com/febaisi/CustomTextView Just add the library compile and add this custom component. Everything by XML. – febaisi
upvote
  flag
to avoid the memory problem, just define your typeface in a static global variable in your Application class then use that single instance everywhere. – M D P
upvote
  flag
@chedabob so maintaining such map isn't required for 4.0+, is that correct to say? – AA_PV

Here's a tutorial that shows you how to setup a custom font like @peter described: http://responsiveandroid.com/2012/03/15/custom-fonts-in-android-widgets.html

it also has consideration for potential memory leaks ala http://code.google.com/p/android/issues/detail?id=9904 . Also in the tutorial is an example for setting a custom font on a button.

If you only have one typeface you would like to add, and want less code to write, you can create a dedicated TextView for your specific font. See code below.

package com.yourpackage;
import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;

public class FontTextView extends TextView {
    public static Typeface FONT_NAME;


    public FontTextView(Context context) {
        super(context);
        if(FONT_NAME == null) FONT_NAME = Typeface.createFromAsset(context.getAssets(), "fonts/FontName.otf");
        this.setTypeface(FONT_NAME);
    }
    public FontTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        if(FONT_NAME == null) FONT_NAME = Typeface.createFromAsset(context.getAssets(), "fonts/FontName.otf");
        this.setTypeface(FONT_NAME);
    }
    public FontTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        if(FONT_NAME == null) FONT_NAME = Typeface.createFromAsset(context.getAssets(), "fonts/FontName.otf");
        this.setTypeface(FONT_NAME);
    }
}

In main.xml, you can now add your textView like this:

<com.yourpackage.FontTextView
    android:id="@+id/tvTimer"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="" />
upvote
  flag
do this on init() and save yourself 3x the same call. – ericosg
upvote
  flag
@ericosg i get this error when i use yourthis solution android.view.InflateException: Binary XML file line #9: Error inflating class com.ascent.adwad.utils.CustomTextView – Sagar Devanga
upvote
  flag
@SagarDevanga, hard to help without more information. Perhaps take it as far as you can and make a new question. – ericosg

Peter's answer is the best, but it can be improved by using the styles.xml from Android to customize your fonts for all textviews in your app.

My code is here

This might be a little late, but you need to create a singleton class that returns the custom typeface to avoid memory leaks.

TypeFace class:

public class OpenSans {

private static OpenSans instance;
private static Typeface typeface;

public static OpenSans getInstance(Context context) {
    synchronized (OpenSans.class) {
        if (instance == null) {
            instance = new OpenSans();
            typeface = Typeface.createFromAsset(context.getResources().getAssets(), "open_sans.ttf");
        }
        return instance;
    }
}

public Typeface getTypeFace() {
    return typeface;
}
}

Custom TextView:

public class NativelyCustomTextView extends TextView {

    public NativelyCustomTextView(Context context) {
        super(context);
        setTypeface(OpenSans.getInstance(context).getTypeFace());
    }

    public NativelyCustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setTypeface(OpenSans.getInstance(context).getTypeFace());
    }

    public NativelyCustomTextView(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        setTypeface(OpenSans.getInstance(context).getTypeFace());
    }

}

By xml:

<com.yourpackage.views.NativelyCustomTextView
            android:id="@+id/natively_text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_margin="20dp"
            android:text="@string/natively"
            android:textSize="30sp" /> 

Programmatically:

TextView programmaticallyTextView = (TextView) 
       findViewById(R.id.programmatically_text_view);

programmaticallyTextView.setTypeface(OpenSans.getInstance(this)
                .getTypeFace());
upvote
  flag
Seems to work at runtime, but is it supposed to work in the designer as well? – Magnus Johansson
upvote
  flag
Sure. You can use as xml. @Magnus – Leonardo Cardoso
upvote
  flag
I think you misunderstood, it doesn't seem to work in Design time (Designer preview). (xml != designer). It works fine specified in the Xml layout file compiled into runtime. Anyway, I'm using this extension github.com/danh32/Fontify, which works much better for my needs (it support multiple font styles, regular, bold etc. as well as different fonts names as well as other controls beyond TextView) – Magnus Johansson
upvote
  flag
Now I get it. No, it doesn't work at design time. I haven't work on it yet. – Leonardo Cardoso
upvote
  flag
The above example seems to work fine for me (but indeed, won't show up in the designer). – Wolfgang Schreurs
2 upvote
  flag
The getTypeFace creates a new typeface on every call...this defeats the purpose of the singleton. It should have a static field that is set the first time the call is made and returns the value of the field on subsequent calls. – Steven Pena
upvote
  flag
That's right, @StevenPena! Fixed. – Leonardo Cardoso
upvote
  flag
Great. Thanks. Just two questions, 1) why does the instance need to hold reference to the Context? 2) synchronized (Gothic.class)? – John Pang
1 upvote
  flag
@chiwai you're right! About the first question it doesn't need it. About the second it was a typo. – Leonardo Cardoso
upvote
  flag
One suggestion: Typeface typeface = getTypeface(); setTypeface(OpenSans.getInstance(context).g‌​etTypeFace(), null != typeface ? typeface.getStyle() : Typeface.NORMAL); to preserve the other style set in XML. – John Pang
upvote
  flag
@LeonardoCardoso you are using a Parameterized constructor in OpenSans when u dont even have one. Please clarify my doubt if i am wrong. Your Code : instance = new OpenSans(context); – Sagar Devanga
upvote
  flag
@LeonardoCardoso i got this error when i used your code. Am I missing something. I have used the class in XML android.view.InflateException: Binary XML file line #9: Error inflating class com.ascent.adwad.utils.CustomTextView – Sagar Devanga
upvote
  flag
@SagarDevanga You are right about the constructor... I forgot to remove the parameter. Just check if you are properly using the right references. If so, put your code here of your custom text view and xml you are inflating it on... – Leonardo Cardoso
upvote
  flag
@JohnPang a good suggestion, but it's not necessary because I think we won't create a custom font class to use normal fonts. – Leonardo Cardoso
upvote
  flag
@LeonardoCardoso problem solved. Thanx for the help. I was using android studio and was supposed to create the ASSETS folder under JAVA Main as contrast to RES in eclipse. – Sagar Devanga
upvote
  flag
@LeonardoCardoso Typeface.NORMAL is not "normal fonts" but "normal style". Other options are BOLD, BOLD_ITALIC, ITALIC. developer.android.com/reference/android/graphics/Typeface.ht‌​ml If not call setTypeface, then any typeface settings (bold/italic) from XML will be lost. – John Pang

I'm 3 years late for the party :( However this could be useful for someone who might stumble upon this post.

I've written a library that caches Typefaces and also allow you to specify custom typefaces right from XML. You can find the library here.

Here is how your XML layout would look like, when you use it.

<com.mobsandgeeks.ui.TypefaceTextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hello_world"
    geekui:customTypeface="fonts/custom_font.ttf" />
upvote
  flag
thank you very much, you ROCK ! – Udo
upvote
  flag
@UDcreate you're welcome. – Ragunath Jawahar
upvote
  flag
Hey @Ragunath-jawahar, how would I import the library for a gradle project? I tried compile 'com.mobsandgeeks:android-typeface-textview:1.0' but that didn't work. – aimango
1 upvote
  flag
You'll need an AAR to be able to use it that way. It's not there yet. You can copy the sources and build a Android Studio Library project for now. – Ragunath Jawahar
2 upvote
  flag
where dose your geekui tag come from? – seph
3 upvote
  flag
From the namespace specified in the parent tag - xmlns:geekui="http://schemas.android.com/apk/res-auto" – Ragunath Jawahar
upvote
  flag
is your library solves the problem of @peter answer ?!! the memory problem – Muhammed Refaat
1 upvote
  flag
@MuhammedRefaat, yes it does :) – Ragunath Jawahar
upvote
  flag
great , thanks a lot – Muhammed Refaat

I might have a simple answer for the question without extending the TextView and implementing a long code.

Code :

 TextView tv = (TextView) findViewById(R.id.textview1);
    tv.setTypeface(Typeface.createFromAsset(getAssets(), "font.ttf"));

Place the custom font file in assets folder as usual and try this. It works for me. I just dont understand why peter has given such a huge code for this simple thing or he has given his answer in old version.

Old question, but I sure wish I read this answer here before I started my own search for a good solution. Calligraphy extends the android:fontFamily attribute to add support for custom fonts in your asset folder, like so:

<TextView 
  android:text="@string/hello_world"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:fontFamily="fonts/Roboto-Bold.ttf"/>

The only thing you have to do to activate it is attaching it to the Context of the Activity you're using:

@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(new CalligraphyContextWrapper(newBase));
}

You can also specify your own custom attribute to replace android:fontFamily

It also works in themes, including the AppTheme.

Fontinator is an Android-Library make it easy, to use custom Fonts. https://github.com/svendvd/Fontinator

Using DataBinding :

@BindingAdapter({"bind:font"})
public static void setFont(TextView textView, String fontName){
 textView.setTypeface(Typeface.createFromAsset(textView.getContext().getAssets(), "fonts/" + fontName));
}

In XML:

<TextView
app:font="@{`Source-Sans-Pro-Regular.ttf`}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

font file must be in assets/fonts/

3 upvote
  flag
where would I place that code? – 707

Also can be defined in the xml without creating custom classes

style.xml

<style name="ionicons" parent="android:TextAppearance">
    <!-- Custom Attr-->
    <item name="fontPath">fonts/ionicons.ttf</item>
</style>

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical" >
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="@style/ionicons"
        android:text=""/>
</LinearLayout>

A quick note, because I just always forgot where to put the fonts, its that the font must be inside assets and this folder resides in the same level that res and src, in my case its assets/fonts/ionicons.ttf

Updated Added root layout because this method needs xmlns:app="http://schemas.android.com/apk/res-auto" to work

Update 2 Forgot about a library that I've installed before called Calligraphy

upvote
  flag
This does not work for me. When I try to build this I get the error message: Error:(49, 5) No resource found that matches the given name: attr 'fontPath'. – Stef
upvote
  flag
Try adding xmlns:app="http://schemas.android.com/apk/res-auto" to your root layout, check the updated answer also – norman784
upvote
  flag
The error does not come from the layout XML file but from the styles XML file. It seems that it does not 'know' what a fontPath is. – Stef
upvote
  flag
Your right, forgot that I've a library called Calligrapy – norman784
upvote
  flag
This doesn't work for me – Konstantin Konopko

The best way to do it From Android O preview release is this way
1.)Right-click the res folder and go to New > Android resource directory. The New
Resource Directory window appears.
2.)In the Resource type list, select font, and then click OK.
3.)Add your font files in the font folder.The folder structure below generates R.font.dancing_script, R.font.la_la, and R.font.ba_ba.
4.)Double-click a font file to preview the file's fonts in the editor.

Next we must create a font family

1.)Right-click the font folder and go to New > Font resource file. The New Resource File window appears.
2.)Enter the file name, and then click OK. The new font resource XML opens in the editor.
3.)Enclose each font file, style, and weight attribute in the font tag element. The following XML illustrates adding font-related attributes in the font resource XML:

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
    <font
    android:fontStyle="normal"
    android:fontWeight="400"
    android:font="@font/hey_regular" />
    <font
    android:fontStyle="italic"
    android:fontWeight="400"
    android:font="@font/hey_bababa" />
</font-family>

Adding fonts to a TextView:

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

As from the documentation

Working With Fonts

all the steps are correct.

There are two ways to customize fonts :

!!! my custom font in assets/fonts/iran_sans.ttf

Way 1 : Refrection Typeface.class ||| best way

call FontsOverride.setDefaultFont() in class extends Application, This code will cause all software fonts to be changed, even Toasts fonts

AppController.java

public class AppController extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        //Initial Font
        FontsOverride.setDefaultFont(getApplicationContext(), "MONOSPACE", "fonts/iran_sans.ttf");

    }
}

FontsOverride.java

public class FontsOverride {

    public static void setDefaultFont(Context context, String staticTypefaceFieldName, String fontAssetName) {
        final Typeface regular = Typeface.createFromAsset(context.getAssets(), fontAssetName);
        replaceFont(staticTypefaceFieldName, regular);
    }

    private 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();
        }
    }
}

Way 2: use setTypeface

for special view just call setTypeface() to change font.

CTextView.java

public class CTextView extends TextView {

    public CTextView(Context context) {
        super(context);
        init(context,null);
    }

    public CTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context,attrs);
    }

    public CTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context,attrs);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public CTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context,attrs);
    }

    public void init(Context context, @Nullable AttributeSet attrs) {

        if (isInEditMode())
            return;

        // use setTypeface for change font this view
        setTypeface(FontUtils.getTypeface("fonts/iran_sans.ttf"));

    }
}

FontUtils.java

public class FontUtils {

    private static Hashtable<String, Typeface> fontCache = new Hashtable<>();

    public static Typeface getTypeface(String fontName) {
        Typeface tf = fontCache.get(fontName);
        if (tf == null) {
            try {
                tf = Typeface.createFromAsset(AppController.getInstance().getApplicationContext().getAssets(), fontName);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
            fontCache.put(fontName, tf);
        }
        return tf;
    }

}

Not the answer you're looking for? Browse other questions tagged or ask your own question.