How to set custom font for a whole application in

2020-01-24 07:01发布

Is it possible to set a custom font in an Android application?

I tried what is posted here, but I don't know where my extends Application class is...

Any help?

EDIT:

I tried the following:

  • Add an assets folder and insert the font inside as seen here:

enter image description here

  • Add a new class that extends from Application

  • Call this new class from my AndroidManifest.xml.

  • I went to my style and added it.

MyApp.java:

public class MyApp extends Application {
  @Override
  public void onCreate() {
     super.onCreate();
    FontsOverride.setDefaultFont(this, "DEFAULT", "raleway_regular.ttf");
    //  This FontsOverride comes from the example I posted above
  }
  }

AndroidManifest.xml:

<application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:supportsRtl="true"
      android:name=".MyApp"
      android:theme="@style/AppTheme">
     ....

styles.xml:

 <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:fontFamily">default</item>
 </style>

But my font is still not changning... any idea?

Then the MyApp class is called. But no effect on my fonts...

EDIT2: I realized that my buttons apply the custom font after I set a custom style for my buttons. Here is my custom button style:

<style name="MyButtonStyle" parent="Widget.AppCompat.Button">
    <item name="textAllCaps">false</item>
    <item name="android:textAllCaps">false</item>
</style>

And here is how it looks now:

enter image description here

So: my button is applying the style, but not the TextView. Any idea on why my custom font is not being applied for all items in application?

标签: android
13条回答
迷人小祖宗
2楼-- · 2020-01-24 07:14
  1. At the beginning, you should right-click on your project resources which name res then from new option choose Android Resource Directory and select font form Resource type and press OK, this will create font directory to placing your fonts in it.

enter image description here

  1. Put your .ttf font files in there.

enter image description here

  1. Go to project style file which exists in following path res/values/styles.xml and add styles like that:

    <style name="SansSerifFont">
        <item name="android:fontFamily">sans-serif</item>
    </style>
    
    <style name="OpenSansFont">
        <item name="android:fontFamily">@font/open_sans</item>
    </style>
    
    <style name="IranianSansFont">
        <item name="android:fontFamily">@font/iranian_sans</item>
    </style>
    
    <style name="BYekanFont">
        <item name="android:fontFamily">@font/b_yekan</item>
    </style>
    
    <style name="DroidArabicFont">
        <item name="android:fontFamily">@font/droid_arabic</item>
    </style>
    
  2. Go to your code and write a class like this for changing whole app font:

    public class AppFontManager {
    
        private AppCompatActivity appCompatActivity;
    
        public static final String SANS_SERIF_APP_FONT = "sans_serif";
        public static final String B_YEKAN_APP_FONT = "b_yekan";
        public static final String DROID_ARABIC_APP_FONT = "droid_arabic";
        public static final String IRANIAN_SANS_APP_FONT = "iranian_sans";
        public static final String OPEN_SANS_APP_FONT = "open_sans";
    
        public AppAppearanceManager(AppCompatActivity appCompatActivity) {
            this.appCompatActivity = appCompatActivity;
        }
    
        public void setFont(String fontName){
    
            switch (fontName){
    
                case SANS_SERIF_APP_FONT:{
                    appCompatActivity.getTheme().applyStyle(R.style.SansSerifFont, true);
                    break;
                }
    
                case B_YEKAN_APP_FONT:{
                    appCompatActivity.getTheme().applyStyle(R.style.BYekanFont, true);
                    break;
                }
    
                case DROID_ARABIC_APP_FONT:{
                    appCompatActivity.getTheme().applyStyle(R.style.DroidArabicFont, true);
                    break;
                }
    
                case IRANIAN_SANS_APP_FONT:{
                appCompatActivity.getTheme().applyStyle(R.style.IranianSansFont, true);
                    break;
                }
    
                case OPEN_SANS_APP_FONT:{
                    appCompatActivity.getTheme().applyStyle(R.style.OpenSansFont, true);
                    break;
                }
            }
        }
    }
    

    Because fonts should separately set for each activities, I prefer write a class for it for more clean code.

  3. Then call the class method before activity onCreate super.onCreate(savedInstanceState):

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        new AppAppearanceManager(this).setFont(APP_DEFAULT_FONT);
        super.onCreate(savedInstanceState);
    // Do you stuff there...
    }
    

    Remember that if you want changing font during runtime, write a chosen font in SharedPreferences or etc, then pass chosen font to all activities setFont like above.

查看更多
淡お忘
3楼-- · 2020-01-24 07:17

I have tried font override too but at the end it's not a reliable solution, sadly overriding fonts take more than that. You can either wait for Android O with custom font to comes out or use a third party library.

The last solution that I came across was this library Caligraphy , which was easy to initiate and let you use as many font as you want. While checking its source code I understood why just overriding fonts won't work so even if you don't plan to use it I recommend reading through it once..

Good luck

查看更多
beautiful°
4楼-- · 2020-01-24 07:20

EDIT

uk.co.chrisjenx:calligraphy Lib is not more maintained for latest android version alternative is now https://github.com/InflationX/Calligraphy

dependencies {
    implementation 'io.github.inflationx:calligraphy3:3.1.1'
    implementation 'io.github.inflationx:viewpump:2.0.3'
}

Add your custom fonts to assets/

Usage

For default font

Define your default font using CalligraphyConfig, in your Application class in the #onCreate() method and pass it to the CalligraphyInterceptor that you add to your ViewPump builder.

@Override
public void onCreate() {
    super.onCreate();
    ViewPump.init(ViewPump.builder()
        .addInterceptor(new CalligraphyInterceptor(
                new CalligraphyConfig.Builder()
                    .setDefaultFontPath("fonts/Roboto-RobotoRegular.ttf")
                    .setFontAttrId(R.attr.fontPath)
                    .build()))
        .build());
    //....
}

Inject into Context: Wrap the Activity Context:

@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase));
}

Custom Style

<style name="TextViewCustomFont">
    <item name="fontPath">fonts/RobotoCondensed-Regular.ttf</item>
</style>

For Theme

<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
    <item name="android:textViewStyle">@style/AppTheme.Widget.TextView</item>
</style>

<style name="AppTheme.Widget"/>

<style name="AppTheme.Widget.TextView" parent="android:Widget.Holo.Light.TextView">
    <item name="fontPath">fonts/Roboto-ThinItalic.ttf</item>
</style>

Not more maintained by Developers Below Solution


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

You should have made on assets/ a "New Directory" "fonts" (see below), so in that code "your font path" should be "fonts/SourceSansPro-Regular.ttf". (It's just "fonts..." not "/fonts.." or "assets..")

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!

On Assets you should right-click New Directory, call it "fonts". In the finder put the .ttf font files in there.

enter image description here

Also dont forgot to add below two lines in attrs.xml,if you dont have attrs.xml file,create new file in values.xml

 <attr format="string" name="fontPath"/> 
    <item name="calligraphy_tag_id" type="id"/>
查看更多
ら.Afraid
5楼-- · 2020-01-24 07:22

If you follow the first topic, this should work : Here

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>
查看更多
Melony?
6楼-- · 2020-01-24 07:24

Create assets folder in main folder.add fonts folder in it. add your .ttf file in fonts folder.

Add following in your app Theme:

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

Create class as TypefaceUtil

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

import java.lang.reflect.Field;

public class TypefaceUtil {

    /**
     * Using reflection to override default typeface
     * NOTICE: DO NOT FORGET TO SET TYPEFACE FOR APP THEME AS DEFAULT TYPEFACE WHICH WILL BE OVERRIDDEN
     * @param context to work with assets
     * @param defaultFontNameToOverride for example "monospace"
     * @param customFontFileNameInAssets file name of the font from assets
     */
    public static void overrideFont(Context context, String defaultFontNameToOverride, String customFontFileNameInAssets) {
        try {
            final Typeface customFontTypeface = Typeface.createFromAsset(context.getAssets(), customFontFileNameInAssets);

            final Field defaultFontTypefaceField = Typeface.class.getDeclaredField(defaultFontNameToOverride);
            defaultFontTypefaceField.setAccessible(true);
            defaultFontTypefaceField.set(null, customFontTypeface);
        } catch (Exception e) {
            Log.e("Can not set","Can not set custom font " + customFontFileNameInAssets + " instead of " + defaultFontNameToOverride);
        }
    }
}

Call it in application class or in the Launcher activity

        TypefaceUtil.overrideFont(getApplicationContext(), "fonts/roboto_regular.ttf", "fonts/roboto_regular.ttf"); // font from assets: "assets/fonts/Roboto-Regular.ttf
查看更多
啃猪蹄的小仙女
7楼-- · 2020-01-24 07:25

A work around for kotlin will be this

Gist of the solution https://gist.github.com/Johnyoat/040ca5224071d01b3f3dfc6cd4d026f7

Step One

Put font file under assets/fonts/your_font_file.ttf and Create a kotlin class called TypeFaceUtil

   class TypefaceUtil{

    fun overridefonts(context: Context, defaultFontToOverride:String, customFontFileNameInAssets:String){
        try {
            val customTypeface = Typeface.createFromAsset(context.assets,customFontFileNameInAssets)
            val defaultTypefaceField = Typeface::class.java.getDeclaredField(defaultFontToOverride)
            defaultTypefaceField.isAccessible = true
            defaultTypefaceField.set(null,customTypeface)
        }catch (e:Exception){
            Timber.e("Cannot set font $customFontFileNameInAssets instead of $defaultFontToOverride")
        }
    }
}

Step Two Then in your on onCreate

val typefaceUtil = TypefaceUtil()

typefaceUtil.overridefonts(this,"SERIF","fonts/font_file.ttf")

Step Three

add this to your style

<item name="android:typeface">serif</item>
查看更多
登录 后发表回答