I need to use certain font for my entire application. I have .ttf file for the same. Is it possible to set this as default font, at application start up and then use it elsewhere in the application? When set, how do I use it in my layout XMLs?
-
in android studio 3.0 you can easily set custom fonts : https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml – MHSaffari Dec 17 '18 at 13:44
-
@MHSFisher Fonts in XML is a feature for Android 8.0 (API level 26) – Emad Razavi Oct 12 '19 at 15:47
-
1@EmiRaz please read the doc https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml#using-support-lib. this feature added in support library 26, but support from API 16. – MHSaffari Oct 13 '19 at 05:22
25 Answers
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>
-
This should be the accepted answer. It's an A-class hack but it just works. – MLProgrammer-CiM Nov 25 '13 at 12:02
-
1Very clever solution! Runs the risk of the Typeface names changing or being moved to a new classes, but my guess is they've been what and where they are since Android 1.5 so it's a reasonably-safe hack. You could cache the fields by name for better performance (I'm thinking in the case where an app has themes and allows fonts to be changed out with live/ instant feedback). – Tom Jan 10 '14 at 18:17
-
11
-
2@ChristopherRivera There is `"DEFAULT_BOLD"` but also a private field : `private static Typeface[] sDefaults;` You could try accessing this by reflection and setting `sDefaults[Typeface.ITALIC]` to yourTypeface. See [this.](http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1.1/android/graphics/Typeface.java#Typeface.defaultFromStyle%28int%29) – weston Mar 27 '14 at 09:17
-
Just in case you need a sample for Xamarin: IntPtr cls = JNIEnv.FindClass("android/graphics/Typeface"); IntPtr fld = JNIEnv.GetStaticFieldID(cls, staticTypefaceFieldName, "Landroid/graphics/Typeface;"); JNIEnv.SetStaticField(cls, fld, newTypeface.Handle); Although all these fields are available now as Typeface static properties. – Mikhail May 08 '14 at 11:46
-
1
-
1This solution works except for action bar. Any ideas to change that easily? – Abdullah Umer Jul 10 '14 at 23:03
-
1
-
But how do i get it to change the font for spinners and the action bar? – crushman Aug 26 '14 at 16:27
-
-
I tried that but its still the same. im putting the `FontsOverride.setDefaultFont` in the mainactivity.java file. is it suppose to be somewhere else for the actionbar? – crushman Aug 27 '14 at 01:28
-
@crushman not 100% sure, I think that would be ok. Needs to be first line in on create. But I usually put in an application class. – weston Aug 27 '14 at 06:21
-
my mainactivity extends `ActionBarActivity` the `FontsOverride.setDefaultFont` is the only thing in my onCreate since im using fragments. – crushman Aug 27 '14 at 12:29
-
@crushman Sorry I don't know then. Like I said I put in application class, plus that way the font only gets loaded once. – weston Aug 27 '14 at 13:28
-
Cool, thanks for solution, but In case of DEFAULT it is not working. I even tried setting typeface="normal" but no luck – Pavan Jaju Aug 31 '14 at 18:23
-
Same here - used to work but on Lollipop (Vanilla) device it doesn't work anymore... – Aviel Gross Nov 26 '14 at 08:44
-
Hi weston, I tried this solution as suggested in resources tag. I have put mycustomfonts.ttf file on assets/fonts folder. If i put monospace it works fine. But if put mycustom fonts, it is not working. Application gives me error. Any suggestion? Thanks. – Jay Pandya Nov 28 '14 at 09:41
-
@JayPandya Ask a new question. It's not practical to do this in comments. But note this reportedly doesn't work in lollypop. – weston Nov 28 '14 at 10:21
-
5@weston Never mind. I have achieved it. There was a mistake in my understanding. You have done a great job. Can you just tell me one thing? Why it is not working for DEFAULT Typeface? I have changed Typeface to MONOSPACE as your suggestion and then apply the loginc, it worked. But not working for DEFAULT – Jay Pandya Nov 29 '14 at 03:56
-
@weston in which class do i write this code. FontsOverride.setDefaultFont(this, "DEFAULT", "MyFontAsset.ttf"); – Sagar Devanga Dec 30 '14 at 13:35
-
-
2Native typeface cannot be made error. Fixed, by adding fonts path. "FontsOverride.setDefaultFont(this, "DEFAULT", "fonts/MyFontAsset.ttf"); " – Sai Jan 10 '15 at 04:06
-
-
@Tooto, I don't know, did you? My solution for API 21 is in the answer. – weston Feb 04 '15 at 14:18
-
@weston nope. I cant find any other solutions. But ur vaviant is not an option to me – Tooto Feb 04 '15 at 14:29
-
@Tooto sorry I've not had time to investigate and my solution works for my needs right now. – weston Feb 04 '15 at 14:51
-
I can confirm that on lollipop devices it also does not work with Theme.AppCompat.Light derived themes. Granted it does work 4.x devices. – startoftext Mar 02 '15 at 17:32
-
for me is not working in Android 5, tested in 4.4 and in others before it and works like a charm. Someone knows how to fix it to work in Lolipop? – Hugo Apr 20 '15 at 13:09
-
@Hugo read the bit about Android 5. If that's not suitable, you might be better off asking another question, because not many people will see your comment. – weston Apr 20 '15 at 13:20
-
1
-
3I find it really annoying to have to swap out the default `TextView` everywhere to use custom fonts or use a reflection based solution like this. Combined with the limiting set of fonts available in android, it makes developing good looking apps a lot of hard work. I've added a feature request to the android issue tracker. If you'd like to see this feature, you can star the issue here: https://code.google.com/p/android/issues/detail?id=187475&thanks=187475&ts=1443175244 – Sam Sep 25 '15 at 10:06
-
-
-
1@Sam thanks, I've put that at the top of the question to attract more votes to the issue. – weston Jan 21 '16 at 09:34
-
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
-
1Note that you may run into some memory corruption bugs as a result of this -- but it would only show up as a native crash in a JNI library. From my testing, I found that the problem is that the old Typeface instance that you are *replacing* here ends up getting GC, which calls the finalizer. When it's finalized, the native pointer to the Typeface gets cleaned up as well, but the native Typeface may still be in use, resulting in a corrupted pointer somewhere. I was able to fix that by *keeping* the references to the old/replaced Typeface instances in a static collection. – Joe Mar 24 '16 at 17:42
-
is there a way to do this without getting a copy of DroidSans.ttf (the font i want to use) so we don't have to deal with copyright license? shouldn't DroidSans.ttf be available directly with the Android sdk? This is the default android font. – Lv99Zubat Apr 07 '16 at 14:34
-
1
-
1@ChristopherRivera I tried using DEFAULT_BOLD but it does't change the bold text font can you help me? – Ajay Sivan Aug 26 '16 at 07:48
-
1HURRAH! android O just released with custom font support. My ticket is finally closed. See here for details: https://developer.android.com/preview/features/working-with-fonts.html – Sam Apr 11 '17 at 07:33
-
(also added my own answer covering this method here: http://stackoverflow.com/a/43339559/1137254) – Sam Apr 23 '17 at 21:15
-
-
@MarekCzaplicki in the `assets` folder. I hope I see one more upvote :p – weston Apr 27 '17 at 14:30
-
yeah, you got it. I was too lazy back then to check the implementation of your class. However it doesn't seem to work for me. I have this in AndroidManifest/application `android:theme="@style/AppTheme"` this in Application: `FontsOverride.setDefaultFont(this, "MONOSPACE", "fonts/Roboto-Regular.ttf");` and this in styles.xml `
- monospace
` – Marek Apr 27 '17 at 14:45 -
@MarekCzaplicki Android 5 or greater? Read that bit of the answer if so. And are you sure you're going to actually notice if yours works as Roboto is already an built in font. In fact that's very odd, what you're trying to achieve? – weston Apr 28 '17 at 01:54
-
-
1@MarekCzaplicki what are you trying to achieve? why don't you ask a new question. Comments are not the best place for this. – weston Apr 28 '17 at 12:50
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:
@Override
protected 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!
-
1
-
1True, its very perfect solution, this way i do not have to write different classes to update fonts for menu items , radio button or checkbox fotns. It applies for all !! thanks :) – Manisha Apr 15 '16 at 22:38
-
2Definitely not a perfect solution: Bold / italic / bold-italic styles are overwritten. There is currently no easy way to set those families. – 0101100101 May 11 '16 at 08:37
-
2
-
2To get bold, italic or underline feature, I've used ``, `` and `` in the `strings.xml` file and so far it works. – jlively Mar 25 '17 at 22:53
-
-
works like a charm. Just add an activity as my base activity and that's all – Pouya Samie Apr 28 '18 at 18:09
-
This is outdated. The new Calligraphy is here: https://github.com/InflationX/Calligraphy – Chisko Jul 25 '18 at 23:22
-
I had an issue with changing the font of bottom navigation and couldn't fix it by calligraphy. Does anyone has solved this issue? If yes, how, please? – Emad Razavi Oct 12 '19 at 15:39
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.

- 6,947
- 7
- 46
- 76
-
4I think the best way would be to override textview. This method could get somewhat redundant if you have an application with a lot of views. – zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz Jul 09 '12 at 00:36
-
1It could... but according to the Android specs you want to avoid layouts deeper than 4 levels and 100 views wide (even that's quite a bit). Recursion can be bad in terms of performance, but even if your layout was 20 levels that's not even significant. – Tom Jul 09 '12 at 00:52
-
I would agree that it doesn't have a noticeable impact on perfomance and I am not trying to say your answer is wrong. I just don't like cycling through every view in the layout if I don't need to. Also, by extending TextView, if you want to modify the appearance in another way you would only have to change the code in one spot. – zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz Jul 09 '12 at 01:11
-
if someone does use your solution they should put your code in an abstract class that extends Activity. – zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz Jul 09 '12 at 01:12
-
I use the extend TextView myself and agrees that its a good solution, but if I hadn't already done so its such a pain to edit all of your XML layouts and code to point to your custom TextView. The abstract Activity works, or just leaving the method static and referencing it is what I do in some situations. – Tom Jul 09 '12 at 01:30
-
1Just wanted to add that above code just covers TextViews but ListViews, Alerts, Toasts, Map Markers etc. will still use the system font. – csch May 02 '13 at 10:50
-
Also, this will not work on dynamically created content, like lists. In such a case, you need to manually set the typeface for each dynamically created view (that shows text). – AlikElzin-kilaka Aug 02 '13 at 10:57
-
-
@NiravDangi What about Fragments? All Views get added to a single hierarchy, so this creates a problem if you're attaching & deattaching views, but you could still call this method `onWindowAttach` or within an `onCreateView` if necessary. Maybe create a BaseFragment class that does this for you! – Tom Jan 10 '14 at 17:59
-
@Tom I am calling from `onCreateView` & getting error at `findViewById( android.R.id.content).getRootView();` – Nirav Dangi Jan 13 '14 at 06:07
-
@NiravDangi I should have clarified, call this function from `onCreateView` but referencing your layout! Of course their is no root content because `onCreateView` has to return before it's added to the Window. – Tom Jan 17 '14 at 02:54
-
Thank you for the code, but font doesn't change on ListView and Buttons, either on the Menu. – Bacara Apr 03 '14 at 15:54
-
2guys this function takes 3 parameters, when you call it recursively you passed 2 parameters ??? which is the correct one ? what is reflect?? – MBH Jul 30 '15 at 17:01
-
I have problem on setAppFont((ViewGroup) mChild, mFont); It says "Create method setAppFont or remove 3rd parameter form setAppFont" – IntoTheDeep Aug 09 '17 at 08:25
In summary:
Option#1: Use reflection to apply font (combining weston & Roger Huang's answer):
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) {
if (isVersionGreaterOrEqualToLollipop()) {
Map<String, Typeface> newMap = new HashMap<String, Typeface>();
newMap.put("sans-serif", newTypeface);
try {
final Field staticField = Typeface.class.getDeclaredField("sSystemFontMap");
staticField.setAccessible(true);
staticField.set(null, newMap);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} else {
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();
}
}
}
}
Usage in 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");
}
}
set up a style to force that font typeface application wide (based on lovefish):
Pre-Lollipop:
<resources>
<style name="AppBaseTheme" parent="Theme.AppCompat.Light">
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:typeface">monospace</item>
</style>
</resources>
Lollipop (API 21):
<resources>
<style name="AppBaseTheme" parent="Theme.AppCompat.Light">
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:textAppearance">@style/CustomTextAppearance</item>
</style>
<style name="CustomTextAppearance">
<item name="android:typeface">monospace</item>
</style>
</resources>
Option2: Subclass each and every View where you need to customize font, ie. ListView, EditTextView, Button, etc. (Palani's answer):
public class CustomFontView extends TextView {
public CustomFontView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public CustomFontView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomFontView(Context context) {
super(context);
init();
}
private void init() {
if (!isInEditMode()) {
Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "Futura.ttf");
setTypeface(tf);
}
}
Option 3: Implement a View Crawler that traverses through the view hierarchy of your current screen:
Variation#1 (Tom's answer):
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... */ }
}
}
}
Usage :
final ViewGroup mContainer = (ViewGroup) findViewById(
android.R.id.content).getRootView();
HomeActivity.setAppFont(mContainer, Typeface.createFromAsset(getAssets(),
"fonts/MyFont.ttf"));
Variation#2: https://coderwall.com/p/qxxmaa/android-use-a-custom-font-everywhere.
Option #4: Use 3rd Party Lib called Calligraphy.
Personally, I would recommend Option#4, as it saves a lot of headaches.
-
In *Option#1*, what do you mean by `"sans-serif"` in `newMap.put(`, and `monospace` in `styles` ?! I want to use a custom font named `barana.ttf`. – Dr.jacky Feb 15 '18 at 06:27
-
in option 1, the first code snippet does not work with API level 22 , Android 5.1.1 . But the other code section does. What should be the exact if condition so ? – user1510006 Dec 25 '18 at 19:03
I would like to improve weston's answer for API 21 Android 5.0.
Cause
Under API 21, most of the text styles include fontFamily setting, like:
<style name="TextAppearance.Material">
<item name="fontFamily">@string/font_family_body_1_material</item>
</style>
Which applys the default Roboto Regular font:
<string name="font_family_body_1_material">sans-serif</string>
The original answer fails to apply monospace font, because android:fontFamily has greater priority to android:typeface attribute (reference). Using Theme.Holo.* is a valid workaround, because there is no android:fontFamily settings inside.
Solution
Since Android 5.0 put system typeface in static variable Typeface.sSystemFontMap (reference), we can use the same reflection technique to replace it:
protected static void replaceFont(String staticTypefaceFieldName,
final Typeface newTypeface) {
if (isVersionGreaterOrEqualToLollipop()) {
Map<String, Typeface> newMap = new HashMap<String, Typeface>();
newMap.put("sans-serif", newTypeface);
try {
final Field staticField = Typeface.class
.getDeclaredField("sSystemFontMap");
staticField.setAccessible(true);
staticField.set(null, newMap);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} else {
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();
}
}
}

- 1
- 1

- 597
- 1
- 8
- 15
-
4nice workaround for L. however, I'm wondering why this doesn't seem to work for my `Button`s and Tool Bar titles. I'm overriding the default font in MainApplication as follows: `FontsOverride.setDefaultFont(this, "DEFAULT", "MyFontAsset.ttf");`. I'm using Nexus 5, v5.1.1 – kip2 Jun 08 '15 at 13:08
-
3Hey , Thank you This was very helpful, just one thing: this not work at Android 6 (API 22). Then should the code be changed to this: `Build.VERSION.SDK_INT == 21` - That is just in the `API 21` **I test at Nexus with API 22** – Saeid Oct 06 '15 at 13:30
-
Still I'm not able to set custom font using this method in Nexus 9 – Rahul Upadhyay Oct 13 '15 at 07:04
-
2Any one having problem not working for 5.1+. Don't override typeface in your values-v21 styles. – Muhammad Babar Feb 19 '16 at 10:13
-
-
The first code snippet does not work with API level 22 , Android 5.1.1 . But the other code section does. What should be the exact if condition so ? – user1510006 Dec 25 '18 at 10:01
its very simple... 1.Download and put ur custom font in assets..then write one separate class for text view as follows: here i used futura font
public class CusFntTextView extends TextView {
public CusFntTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public CusFntTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CusFntTextView(Context context) {
super(context);
init();
}
private void init() {
if (!isInEditMode()) {
Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "Futura.ttf");
setTypeface(tf);
}
}
}
and do the following in xml :
<com.packagename.CusFntTextView
android:id="@+id/tvtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hi Android"
android:textAppearance="?android:attr/textAppearanceLarge"
/>

- 173
- 1
- 13
-
Yes, that works :) But, what if I want to apply the same fonts for other remaining views/ widgets? Do I need to write separate class for all other views (including dialogs / toasts / actionbars) too? – Narendra Singh Sep 03 '15 at 18:25
-
Yes, for this solution you need to write separate classes for each of your view. – Saad Bilal Aug 20 '16 at 06:05
I would also suggest extending TextView and other controls, but it would be better I consider to set up font in constructs.
public FontTextView(Context context) {
super(context);
init();
}
public FontTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public FontTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
protected void init() {
setTypeface(Typeface.createFromAsset(getContext().getAssets(), AppConst.FONT));
}

- 2,626
- 21
- 19
-
2Be careful when doing this on platforms before 4.0 - this will leak a lot of resources due to a bug in Android: https://code.google.com/p/android/issues/detail?id=9904 – Ryan M Jun 20 '13 at 21:52
-
how can we revert back to default. I am doing something like this: if(configShared.getString("storeId", AppCredentials.DEFAULT_STORE_ID).equals("2")){ final Field staticField = Typeface.class.getDeclaredField(staticTypefaceFieldName); staticField.setAccessible(true); staticField.set(null, newTypeface); } else{ final Field staticField = Typeface.class.getDeclaredField(staticTypefaceFieldName); staticField.setAccessible(true); staticField.set(null, null); } – Shubham AgaRwal Feb 15 '16 at 15:51
I would like to improve weston's and Roger Huang's answers for over API 21 Android lollipop with theme "Theme.AppCompat".
Below Android 4.4
<resources>
<style name="AppBaseTheme" parent="Theme.AppCompat.Light">
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:typeface">monospace</item>
</style>
</resources>
Over(equal) API 5.0
<resources>
<style name="AppBaseTheme" parent="Theme.AppCompat.Light">
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:textAppearance">@style/CustomTextAppearance</item>
</style>
<style name="CustomTextAppearance">
<item name="android:typeface">monospace</item>
</style>
</resources>
And the FontsOverride util file is same as what in weston's answer. I have tested in these phones:
Nexus 5(android 5.1 Primary Android System)
ZTE V5(android 5.1 CM12.1)
XIAOMI note(android 4.4 MIUI6)
HUAWEI C8850(android 2.3.5 UNKNOWN)
A brilliant solution can be found here: https://coderwall.com/p/qxxmaa/android-use-a-custom-font-everywhere.
Simply extend activities from BaseActivity and write those methods. Also you should better cache fonts as described here: https://stackoverflow.com/a/16902532/2914140.
After some research I wrote code that works at Samsung Galaxy Tab A (Android 5.0). Used code of weston and Roger Huang as well as https://stackoverflow.com/a/33236102/2914140. Also tested on Lenovo TAB 2 A10-70L, where it doesn't work. I inserted a font 'Comic Sans' here in order to see a difference.
import android.content.Context;
import android.graphics.Typeface;
import android.os.Build;
import android.util.Log;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class FontsOverride {
private static final int BOLD = 1;
private static final int BOLD_ITALIC = 2;
private static final int ITALIC = 3;
private static final int LIGHT = 4;
private static final int CONDENSED = 5;
private static final int THIN = 6;
private static final int MEDIUM = 7;
private static final int REGULAR = 8;
private Context context;
public FontsOverride(Context context) {
this.context = context;
}
public void loadFonts() {
Map<String, Typeface> fontsMap = new HashMap<>();
fontsMap.put("sans-serif", getTypeface("comic.ttf", REGULAR));
fontsMap.put("sans-serif-bold", getTypeface("comic.ttf", BOLD));
fontsMap.put("sans-serif-italic", getTypeface("comic.ttf", ITALIC));
fontsMap.put("sans-serif-light", getTypeface("comic.ttf", LIGHT));
fontsMap.put("sans-serif-condensed", getTypeface("comic.ttf", CONDENSED));
fontsMap.put("sans-serif-thin", getTypeface("comic.ttf", THIN));
fontsMap.put("sans-serif-medium", getTypeface("comic.ttf", MEDIUM));
overrideFonts(fontsMap);
}
private void overrideFonts(Map<String, Typeface> typefaces) {
if (Build.VERSION.SDK_INT == 21) {
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", "Cannot set custom fonts");
}
} else {
try {
for (Map.Entry<String, Typeface> entry : typefaces.entrySet()) {
final Field staticField = Typeface.class.getDeclaredField(entry.getKey());
staticField.setAccessible(true);
staticField.set(null, entry.getValue());
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
private Typeface getTypeface(String fontFileName, int fontType) {
final Typeface tf = Typeface.createFromAsset(context.getAssets(), "fonts/" + fontFileName);
return Typeface.create(tf, fontType);
}
}
To run the code in entire application you should write in some class like Application the following:
new FontsOverride(this).loadFonts();
Create a folder 'fonts' inside 'assets' and put needed fonts there. A simple instruction may be found here: https://stackoverflow.com/a/31697103/2914140.
The Lenovo device also incorrectly gets a value of a typeface. In most times it returns Typeface.NORMAL, sometimes null. Even if a TextView is bold (in xml-file layout). See here: TextView isBold always returns NORMAL. This way a text on a screen is always in a regural font, not bold or italic. So I think it's a bug of a producer.
-
I studied android source code, your answer is the best best one. It can replace thin, medium, light or anything else. Thank you so much! – momvart Aug 03 '17 at 09:44
Working for Xamarin.Android:
Class:
public class FontsOverride
{
public static void SetDefaultFont(Context context, string staticTypefaceFieldName, string fontAssetName)
{
Typeface regular = Typeface.CreateFromAsset(context.Assets, fontAssetName);
ReplaceFont(staticTypefaceFieldName, regular);
}
protected static void ReplaceFont(string staticTypefaceFieldName, Typeface newTypeface)
{
try
{
Field staticField = ((Java.Lang.Object)(newTypeface)).Class.GetDeclaredField(staticTypefaceFieldName);
staticField.Accessible = true;
staticField.Set(null, newTypeface);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
Application Implementation:
namespace SomeAndroidApplication
{
[Application]
public class App : Application
{
public App()
{
}
public App(IntPtr handle, JniHandleOwnership transfer)
: base(handle, transfer)
{
}
public override void OnCreate()
{
base.OnCreate();
FontsOverride.SetDefaultFont(this, "MONOSPACE", "fonts/Roboto-Light.ttf");
}
}
}
Style:
<style name="Theme.Storehouse" parent="Theme.Sherlock">
<item name="android:typeface">monospace</item>
</style>

- 378
- 1
- 4
- 11
As of Android O this is now possible to define directly from the XML and my bug is now closed!
TL;DR:
First you must add your fonts to the project
Second you add a font family, like so:
<?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/lobster_regular" />
<font
android:fontStyle="italic"
android:fontWeight="400"
android:font="@font/lobster_italic" />
</font-family>
Finally, you can use the font in a layout or style:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/lobster"/>
<style name="customfontstyle" parent="@android:style/TextAppearance.Small">
<item name="android:fontFamily">@font/lobster</item>
</style>
Enjoy!

- 3,453
- 1
- 33
- 57
-
Thanks. We should use Android Studio 2.4 to able to add font folder. – Photon Point Apr 21 '17 at 07:48
-
actually I just need to apply it to my style and it'll be applied through the application. but some (programmatically added controls will need to be applied through java code) – Desolator Aug 28 '17 at 03:30
You can set custom fonts for every layout one by one ,with just one function call from every layout by passing its root View.First ,create a singelton approach for accessing font object like this
public class Font {
private static Font font;
public Typeface ROBO_LIGHT;
private Font() {
}
public static Font getInstance(Context context) {
if (font == null) {
font = new Font();
font.init(context);
}
return font;
}
public void init(Context context) {
ROBO_LIGHT = Typeface.createFromAsset(context.getAssets(),
"Roboto-Light.ttf");
}
}
You can define different fonts in above class, Now Define a font Helper class that will apply fonts :
public class FontHelper {
private static Font font;
public static void applyFont(View parentView, Context context) {
font = Font.getInstance(context);
apply((ViewGroup)parentView);
}
private static void apply(ViewGroup parentView) {
for (int i = 0; i < parentView.getChildCount(); i++) {
View view = parentView.getChildAt(i);
//You can add any view element here on which you want to apply font
if (view instanceof EditText) {
((EditText) view).setTypeface(font.ROBO_LIGHT);
}
if (view instanceof TextView) {
((TextView) view).setTypeface(font.ROBO_LIGHT);
}
else if (view instanceof ViewGroup
&& ((ViewGroup) view).getChildCount() > 0) {
apply((ViewGroup) view);
}
}
}
}
In the above code, I am applying fonts on textView and EditText only , you can apply fonts on other view elements as well similarly.You just need to pass the id of your root View group to the above apply font method. for example your layout is :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/mainParent"
tools:context="${relativePackage}.${activityClass}" >
<RelativeLayout
android:id="@+id/mainContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/homeFooter"
android:layout_below="@+id/edit" >
<ImageView
android:id="@+id/PreviewImg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/abc_list_longpressed_holo"
android:visibility="gone" />
<RelativeLayout
android:id="@+id/visibilityLayer"
android:layout_width="match_parent"
android:layout_height="fill_parent" >
<ImageView
android:id="@+id/UseCamera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:src="@drawable/camera" />
<TextView
android:id="@+id/tvOR"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/UseCamera"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:text="OR"
android:textSize="30dp" />
<TextView
android:id="@+id/tvAND"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:text="OR"
android:textSize="30dp" />
</RelativeLayout>
In the Above Layout the root parent id is "Main Parent " now lets apply font
public class MainActivity extends BaseFragmentActivity {
private EditText etName;
private EditText etPassword;
private TextView tvTitle;
public static boolean isHome = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Font font=Font.getInstance(getApplicationContext());
FontHelper.applyFont(findViewById(R.id.mainParent), getApplicationContext());
}
}
Cheers :)
-
Nice.. no more same font re-create, only 1 font use for all field. :) – Arfan Mirza Mar 13 '15 at 10:30
I would suggest extending TextView, and always using your custom TextView within your XML layouts or wherever you need a TextView. In your custom TextView, override setTypeface
@Override
public void setTypeface(Typeface tf, int style) {
//to handle bold, you could also handle italic or other styles here as well
if (style == 1){
tf = Typeface.createFromAsset(getContext().getApplicationContext().getAssets(), "MuseoSans700.otf");
}else{
tf = Typeface.createFromAsset(getContext().getApplicationContext().getAssets(), "MuseoSans500.otf");
}
super.setTypeface(tf, 0);
}

- 40,335
- 6
- 42
- 42
Tom's solution works great, but only works with TextView and EditText.
If you want to cover most of the views (RadioGroup, TextView, Checkbox...), I created a method doing that :
protected void changeChildrenFont(ViewGroup v, Typeface font){
for(int i = 0; i < v.getChildCount(); i++){
// For the ViewGroup, we'll have to use recursivity
if(v.getChildAt(i) instanceof ViewGroup){
changeChildrenFont((ViewGroup) v.getChildAt(i), font);
}
else{
try {
Object[] nullArgs = null;
//Test wether setTypeface and getTypeface methods exists
Method methodTypeFace = v.getChildAt(i).getClass().getMethod("setTypeface", new Class[] {Typeface.class, Integer.TYPE});
//With getTypefaca we'll get back the style (Bold, Italic...) set in XML
Method methodGetTypeFace = v.getChildAt(i).getClass().getMethod("getTypeface", new Class[] {});
Typeface typeFace = ((Typeface)methodGetTypeFace.invoke(v.getChildAt(i), nullArgs));
//Invoke the method and apply the new font with the defined style to the view if the method exists (textview,...)
methodTypeFace.invoke(v.getChildAt(i), new Object[] {font, typeFace == null ? 0 : typeFace.getStyle()});
}
//Will catch the view with no such methods (listview...)
catch (Exception e) {
e.printStackTrace();
}
}
}
}
This method will get back the style of the view set in XML (bold, italic...) and apply them if they exists.
For the ListView, I always create an adapter, and I set the font inside getView.

- 2,011
- 4
- 29
- 42
I wrote a class assigning typeface to the views in the current view hierarchy and based os the current typeface properties (bold, normal, you can add other styles if you want):
public final class TypefaceAssigner {
public final Typeface DEFAULT;
public final Typeface DEFAULT_BOLD;
@Inject
public TypefaceAssigner(AssetManager assetManager) {
DEFAULT = Typeface.createFromAsset(assetManager, "TradeGothicLTCom.ttf");
DEFAULT_BOLD = Typeface.createFromAsset(assetManager, "TradeGothicLTCom-Bd2.ttf");
}
public void assignTypeface(View v) {
if (v instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) v).getChildCount(); i++) {
View view = ((ViewGroup) v).getChildAt(i);
if (view instanceof ViewGroup) {
setTypeface(view);
} else {
setTypeface(view);
}
}
} else {
setTypeface(v);
}
}
private void setTypeface(View view) {
if (view instanceof TextView) {
TextView textView = (TextView) view;
Typeface typeface = textView.getTypeface();
if (typeface != null && typeface.isBold()) {
textView.setTypeface(DEFAULT_BOLD);
} else {
textView.setTypeface(DEFAULT);
}
}
}
}
Now in all fragments in onViewCreated or onCreateView, in all activities in onCreate and in all view adapters in getView or newView just invoke:
typefaceAssigner.assignTypeface(view);

- 956
- 8
- 9
in api 26 with build.gradle 3.0.0 and higher you can create a font directory in res and use this line in your style
<item name="android:fontFamily">@font/your_font</item>
for change build.gradle use this in your build.gradle dependecies
classpath 'com.android.tools.build:gradle:3.0.0'

- 2,169
- 1
- 8
- 8
-
-
-
yeah, tanx. I already got that. But that `item` alone doesn't set the font for the entire app. any clue? – azerafati Jan 20 '18 at 13:47
Finally, Google realized the severity of this problem (applying custom font to UI components) and they devised a clean solution for it.
First, you need to update to support library 26+ (you may also need to update your gradle{4.0+}, android studio), then you can create a new resource folder called font. In this folder, you can put your font resources (.tff,...). Then you need to override the default app them and force your custom font into it :)
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:fontFamily">@font/my_custom_font</item>
</style>
Note: if you want to support devices with older API than 16, you have to use app namespace instead of android!

- 4,316
- 3
- 43
- 40
I would also like to improve weston's answer for API 21 Android 5.0.
I had the same issue on my Samsung s5, when using DEFAULT font. (with the others fonts it's working fine)
I managed to make it working by setting the typeface ("sans" for example) in XML files, for each Textview or Button
<TextView
android:layout_width="match_parent"
android:layout_height="39dp"
android:textColor="@color/abs__background_holo_light"
android:textSize="12sp"
android:gravity="bottom|center"
android:typeface="sans" />
and in MyApplication Class :
public class MyApplication extends Application {
@Override
public void onCreate() {
TypefaceUtil.overrideFont(getApplicationContext(), "SANS_SERIF",
"fonts/my_font.ttf");
}
}
Hope it helps.

- 211
- 1
- 6
This solution does not work correctly in some situations.
So I extend it:
FontsReplacer.java
public class MyApplication extends Application {
@Override
public void onCreate() {
FontsReplacer.replaceFonts(this);
super.onCreate();
}
}
https://gist.github.com/orwir/6df839e3527647adc2d56bfadfaad805
Calligraphy works pretty well, but it is not suitable for me, since it does not support different weights (bold, italic, etc) for a font-family.
So I tried Fontain, which allows you to define custom Views and apply them custom font families.
in order to use Fontain, you should add the following to your app module build.gradle:
compile 'com.scopely:fontain:1.0.0'
Then, instead of using regular TextView, you should use FontTextView
Example of FontTextView with uppercase and bold content:
<com.scopely.fontain.views.FontTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/black"
android:textColor="@android:color/white"
android:textSize="11dp"
android:gravity="center"
android:id="@+id/tv1"
app:font_family="myCustomFont"
app:caps_mode="characters"
app:font_weight="BOLD"/>

- 774
- 9
- 32
package com.theeasylearn.demo.designdemo;
import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;
public class MyButton extends TextView {
public MyButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyButton(Context context) {
super(context);
init();
}
private void init() {
Typeface tf =
Typeface.createFromAsset(
getContext().getAssets(), "angelina.TTF");
setTypeface(tf);
}
}

- 797
- 11
- 22
-
Not a perfect solution. Using this solution will require custom workarounds to access default Android `TextView`s – blueware Jul 09 '17 at 07:07
For changing default font family of the TextViews, override textViewStyle in your app theme.
For using custom font in fontFamily, use font resources which is in support library.
The feature was added in Android 26 but backported to older versions via supportlib.
https://developer.android.com/guide/topics/resources/font-resource.html https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml.html#using-support-lib

- 495
- 2
- 11
Since the release of Android Oreo and its support library (26.0.0) you can do this easily. Refer to this answer in another question.
Basically your final style will look like this:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="fontFamily">@font/your_font</item> <!-- target android sdk versions < 26 and > 14 -->
</style>

- 2,785
- 2
- 13
- 17
I found the mixture of calligraphy 3 library and coderwall's post as my ultimate result.

- 1,903
- 2
- 17
- 24
Yes, its possible to set the font to the entire application.
The easiest way to accomplish this is to package the desired font(s) with your application.
To do this, simply create an assets/ folder in the project root, and put your fonts (in TrueType, or TTF, form) in the assets.
You might, for example, create assets/fonts/ and put your TTF files in there.
public class FontSampler extends Activity {
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
TextView tv=(TextView)findViewById(R.id.custom);
Typeface face=Typeface.createFromAsset(getAssets(), "fonts/HandmadeTypewriter.ttf");
tv.setTypeface(face);
}
}

- 12,439
- 6
- 36
- 59

- 65
- 2