如何在棒棒糖中为整个应用程序设置自定义字体

how to set custom font for entire application in lollipop

我想为我的 app.I 中使用的所有文本视图设置自定义字体,代码如下

public static void overrideFont(Context context, String defaultFontNameToOverride, String customFontFileNameInAssets)
    {
        try
        {
            final Typeface customFontTypeface = Typeface.createFromAsset(context.getAssets(),customFontFileNameInAssets);
            Field defaultFontTypefaceField = Typeface.class.getDeclaredField(defaultFontNameToOverride);
            defaultFontTypefaceField.setAccessible (true);
            defaultFontTypefaceField.set(null,customFontTypeface);
        }
        catch (Exception e)
        {
            Log.e("getMessage",e.getMessage());
            e.printStackTrace();
            //Log.e("Can not set custom font " + customFontFileNameInAssets + " instead of " + defaultFontNameToOverride);
        }

    }

调用方法如下

TypefaceUtil.overrideFont(this, "DEFAULT", getTypeFace());
        TypefaceUtil.overrideFont(this, "MONOSPACE", getTypeFace());
        TypefaceUtil.overrideFont(this, "SERIF", getTypeFace());
        TypefaceUtil.overrideFont(this, "SANS_SERIF", getTypeFace());

此代码在 android 之前在 android 5 中有效,但在 lollipop 中不起作用。 我搜索了很多,但我没有找到任何东西。

我用 Calligraphy

做到了

在您的应用程序中 class 在 #onCreate() 方法中。

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

包装 Activity 上下文:

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

假设你选择的字体是serif-monospace,那么你也应该像

一样实现
<style name="TextView" parent="android:Widget.TextView">
        <item name="android:fontFamily">serif-monospace</item>
    </style>

并像这样使用

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

我通过覆盖应用程序默认字体来完成它:

创建 class FontsOverride:

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

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

创建一个 Application Class 或将其添加到您当前的一个,如果您已经拥有:

public class AppController extends Application {

// add a folder named `fonts` under `assets` folder
// add theme here
String customFont1 = "fonts/IRANSans-Light-web.ttf";
String customFont2 = "fonts/font2.ttf";
String customFont3 = "fonts/font3.ttf";
String customFont4 = "fonts/font4.ttf";

@Override
public void onCreate() {
    super.onCreate();
    // override default fonts
    FontsOverride.setDefaultFont(this, "DEFAULT", customFont1);
    FontsOverride.setDefaultFont(this, "MONOSPACE", customFont2);
    FontsOverride.setDefaultFont(this, "SERIF", customFont3);
    FontsOverride.setDefaultFont(this, "SANS_SERIF", customFont4);

}

}

style

中为您的主题添加字体
<!-- Application theme -->
<style name="myTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:typeface">monospace</item>
</style>

最后,将其添加到 Application 标签中的 manifest

    <application
    android:name="path.AppController"
    android:icon="@mipmap/ic_launcher"
    android:theme="@style/myTheme"
    android:label="@string/app_name">

(我已经测试过了,它也适用于`Lolipop)

我创建了一个递归函数并将其保存在我的 BaseActivity 中:

 public static void overrideFonts(final Context context, final View v) {
    try {
        if (v instanceof ViewGroup) {
            ViewGroup vg = (ViewGroup) v;
            for (int i = 0; i < vg.getChildCount(); i++) {
                View child = vg.getChildAt(i);
                overrideFonts(context, child);
            }
        }
        if (v.getClass() == TextView.class) {
            if (v.getTag() != null && v.getTag().toString().equalsIgnoreCase("bold")) {
                ((TextView) v).setTypeface(FontUtils.getFontBold(context));
            } else {
                ((TextView) v).setTypeface(FontUtils.getFont(context));
            }
        }

        if (v.getClass() == AppCompatTextView.class) {
            if (v.getTag() != null && v.getTag().toString().equalsIgnoreCase("bold")) {
                ((TextView) v).setTypeface(FontUtils.getFontBold(context));
            } else {
                ((TextView) v).setTypeface(FontUtils.getFont(context));
            }
        }

        if (v.getClass() == Button.class) {
            ((Button) v).setTypeface(FontUtils.getFontBold(context));
        }
        if (v.getClass() == AppCompatButton.class) {
            ((Button) v).setTypeface(FontUtils.getFontBold(context));
        }

        if (v.getClass() == TextInputLayout.class) {
            ((TextInputLayout) v).setTypeface(FontUtils.getFontBold(context));
        }
        if (v.getClass() == TextInputEditText.class) {
            ((TextInputEditText) v).setTypeface(FontUtils.getFont(context));
        }
        if (v.getClass() == AppCompatEditText.class) {
            ((AppCompatEditText) v).setTypeface(FontUtils.getFont(context));
        }
        if (v.getClass() == EditText.class) {
            if (v.getTag() != null && v.getTag().toString().equalsIgnoreCase("bold")) {
                ((EditText) v).setTypeface(FontUtils.getFontBold(context));
            } else {
                ((EditText) v).setTypeface(FontUtils.getFont(context));
            }
        }
    } catch (Exception e) {
        Log.e("Font Exception", e.toString());
    }
}

字体实用程序:

public abstract class FontUtils {

    public static Typeface regular, bold;

    public static Typeface getFont(Context appContext) {
    if (regular == null) {
        regular = Typeface.createFromAsset(appContext.getAssets(), "fonts/Lato-Regular.ttf");
    }
    return regular;
    }


    public static Typeface getFontBold(Context appContext) {
    if (bold == null) {
        bold = Typeface.createFromAsset(appContext.getAssets(), "fonts/Lato-Bold.ttf");
    }
    return bold;
    }
}

您可以添加自己的案例,而且我使用 xml 中的标签来显示粗体和常规字体

android:tag="bold"

像这样在 BaseActivity 的 onCreate 中调用方法:

View contentView = this.findViewById(android.R.id.content);
overrideFonts(this, contentView);

确保在 activity 中的 setContentView 之后调用 super.OnCreate。

希望这对您有所帮助。

检查一下:Working with fonts

从 I/O 2017 年起,您现在可以在 xml 中使用以下内容:

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

Google 添加了对 O 设备的支持,而且,我引用:

The Support Library 26.0 Beta provides support to the Fonts in XML feature on devices running Android API version 14 and higher.