如何为整个Android应用设置默认字体系列


282

我在应用中使用了Roboto light字体。要设置字体,我必须将其添加android:fontFamily="sans-serif-light"到每个视图中。有没有办法将Roboto字体声明为整个应用程序的默认字体系列?我已经尝试过这种方法,但是似乎没有用。

<style name="AppBaseTheme" parent="android:Theme.Light"></style>

<style name="AppTheme" parent="AppBaseTheme">
    <item name="android:fontFamily">sans-serif-light</item>
</style>

2
这可能会对您有所帮助:stackoverflow.com/a/16883281/1329733
Jacob R

2
现在,您可以直接从该XML指定自定义字体在Android Studio中3.0 developer.android.com/guide/topics/ui/look-and-feel/...

Answers:


289

答案是肯定的。

Global Roboto light适用于TextViewButton类:

<style name="AppTheme" parent="AppBaseTheme">
    <item name="android:textViewStyle">@style/RobotoTextViewStyle</item>
    <item name="android:buttonStyle">@style/RobotoButtonStyle</item>
</style>

<style name="RobotoTextViewStyle" parent="android:Widget.TextView">
    <item name="android:fontFamily">sans-serif-light</item>
</style>

<style name="RobotoButtonStyle" parent="android:Widget.Holo.Button">
    <item name="android:fontFamily">sans-serif-light</item>
</style>

只需从themes.xml列表中选择所需的样式,然后基于原始样式创建自定义样式。最后,将样式用作应用程序的主题。

<application
    android:theme="@style/AppTheme" >
</application>

它只能与Roboto等内置字体一起使用,但这是问题所在。对于自定义字体(例如,从资产加载),此方法将不起作用。

编辑15年8月13日

如果您使用的是AppCompat主题,请记住删除android:前缀。例如:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:textViewStyle">@style/RobotoTextViewStyle</item>
    <item name="buttonStyle">@style/RobotoButtonStyle</item>
</style>

注意,buttonStyle不包含android:前缀,但textViewStyle必须包含前缀。


4
sans-serif-light从何处获得价值?是否有fontFamily某个地方的有效值列表?我一直在浏览文档以及Android源代码中的主题和样式文件,但找不到任何东西。
克里斯托弗·佩里

34
这仅适用于API级别16。名称“ android:fontFamily”仅存在于级别16或更高版本中。是否有办法例如针对API 14?
Lorenzo Barbagli 2013年

3
@LorenzoBarbagli,您可以检查书法
Brais加宾

10
那么,如果我有自定义字体怎么办?
罗希特·提格

2
是的,我也想向整个应用程序添加自定义字体。我怎样才能做到这一点 ?。我是否需要覆盖TextView并替换第一个答案中建议的所有TextView
John

144

随着Android Oreo的发布,您可以使用支持库来实现此目标。

  1. 如果您的支持库> = 26.0.0,请入您的app build.gradle
  2. 将“ font ”文件夹添加到资源文件夹,然后在其中添加字体
  3. 在您的应用主样式中引用默认字体系列:

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
       <item name="android:fontFamily">@font/your_font</item>
       <item name="fontFamily">@font/your_font</item> <!-- target android sdk versions < 26 and > 14 if theme other than AppCompat -->
    </style>

查看https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml.html了解更多详细信息。


9
定位到API 26+时,这应该是公认的方法。使用支持库时,只需删除android:前缀
webo80'9

2
如果仅使用无前缀版本,则可以。在API <26
webo80'9

2
这不会在所有地方设置字体...例如,如果您有从衍生的样式Base.TextAppearance.AppCompat,那么就不会在其中使用它。
Ixx

3
@Ixx,如何也覆盖这些样式?
普里莫兹Kralj

2
记住,针对api <26时也要使用AppCompatTextView
Codelicious

37

要更改您的应用字体,请执行以下步骤:

  1. res目录内部创建新目录并调用它font
  2. 将您的字体.ttf / .otf插入字体文件夹中,确保字体名称为小写字母和下划线。
  3. 内部res-> values-> styles.xml内部<resources>-> <style>添加字体<item name="android:fontFamily">@font/font_name</item>

在此处输入图片说明

现在,您所有的应用程序文本都将位于您添加的文本中。


8
使用自定义字体时,如何添加粗体字体和常规字体?
拉吉尔·希恩

仅适用于26级及以上的API,API 21及以下如何?
zulkarnain shah

34

阅读下面的更新

我在嵌入新字体时遇到了同样的问题,最后使它与扩展TextView并在其中设置typefont一起使用。

public class YourTextView extends TextView {

    public YourTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public YourTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public YourTextView(Context context) {
        super(context);
        init();
    }

    private void init() {
        Typeface tf = Typeface.createFromAsset(context.getAssets(),
            "fonts/helveticaneue.ttf");
        setTypeface(tf);
    }
}

您必须稍后将每个元素中的TextView元素从更改为。而且,如果您在Eclipse中使用UI-Creator,有时他不会正确显示TextViews。是唯一对我有用的东西...

更新

如今,我正在使用反射来更改整个应用程序中的字体,而无需扩展TextViews。查看此SO帖子

更新2

从API级别26开始并在“支持库”中可用,您可以使用

android:fontFamily="@font/embeddedfont"

更多信息:XML字体


25
这不是解决方案。我正在使用许多不同的视图,不仅是TextView。我只想设置一次字体,然后就忘了。此外,您的代码为每个TextView创建一个新对象。至少将字段声明为静态,以从资产中加载一次字体。
tomrozb

2
...好吧,有一个查找和替换功能,在这种情况下非常有效
longi

1
这行不通。getContext()当变量为静态时,您无法调用。您应该以单例方式实现它,否则当前代码甚至无法编译。
tomrozb 2015年

1
我还原了最后一次提交。
隆迪

1
@tomrozb:D我刚刚意识到,我所做的最后一次快速更改是因为您的评论!如果您有足够的观点,欢迎您自己优化代码示例。否则,我们将在几年之内仍然谈论这个话题,那时没人再在乎智能手机了;)
longi 2015年

8

在您的res / value / styles.xml中添加此行代码

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

整个风格看起来像

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:fontFamily">@font/circular_medium</item>
</style>

将“ circular_medium”更改为您自己的字体名称。


6

更不用说性能了,对于自定义字体,您可以在所有视图中使用递归方法循环,​​如果是TextView,则可以设置字体:

public class Font {
    public static void setAllTextView(ViewGroup parent) {
        for (int i = parent.getChildCount() - 1; i >= 0; i--) {
            final View child = parent.getChildAt(i);
            if (child instanceof ViewGroup) {
                setAllTextView((ViewGroup) child);
            } else if (child instanceof TextView) {
                ((TextView) child).setTypeface(getFont());
            }
        }
    }

    public static Typeface getFont() {
        return Typeface.createFromAsset(YourApplicationContext.getInstance().getAssets(), "fonts/whateverfont.ttf");
    }
}

在您所有的活动中,在setContentView之后将当前的ViewGroup传递给它,并完成该操作:

ViewGroup group = (ViewGroup) getWindow().getDecorView().findViewById(android.R.id.content);
Font.setAllTextView(group);

对于片段,您可以执行类似的操作。


1
听起来不错,但想知道如何使其在recyclerView内容中起作用?
Srujan Barai

我刚试过 太重而无法渲染。recyclerView像地狱一样减速。
Srujan Barai

完全不建议在任何列表视图中使用此技巧,只是为了节省编写静态视图代码的时间。
艾伦·陈

5

对整个应用程序执行此操作的另一种方法是基于此答案使用反射

public class TypefaceUtil {
    /**
     * Using reflection to override default typefaces
     * NOTICE: DO NOT FORGET TO SET TYPEFACE FOR APP THEME AS DEFAULT TYPEFACE WHICH WILL BE
     * OVERRIDDEN
     *
     * @param typefaces map of fonts to replace
     */
    public static void overrideFonts(Map<String, Typeface> typefaces) {
        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", "Can not set custom fonts");
        }
    }

    public static Typeface getTypeface(int fontType, Context context) {
        // here you can load the Typeface from asset or use default ones
        switch (fontType) {
            case BOLD:
                return Typeface.create(SANS_SERIF, Typeface.BOLD);
            case ITALIC:
                return Typeface.create(SANS_SERIF, Typeface.ITALIC);
            case BOLD_ITALIC:
                return Typeface.create(SANS_SERIF, Typeface.BOLD_ITALIC);
            case LIGHT:
                return Typeface.create(SANS_SERIF_LIGHT, Typeface.NORMAL);
            case CONDENSED:
                return Typeface.create(SANS_SERIF_CONDENSED, Typeface.NORMAL);
            case THIN:
                return Typeface.create(SANS_SERIF_MEDIUM, Typeface.NORMAL);
            case MEDIUM:
                return Typeface.create(SANS_SERIF_THIN, Typeface.NORMAL);
            case REGULAR:
            default:
                return Typeface.create(SANS_SERIF, Typeface.NORMAL);
        }
    }
}

然后只要您想覆盖字体,就可以调用方法并为其提供字体映射,如下所示:

Typeface regular = TypefaceUtil.getTypeface(REGULAR, context);
Typeface light = TypefaceUtil.getTypeface(REGULAR, context);
Typeface condensed = TypefaceUtil.getTypeface(CONDENSED, context);
Typeface thin = TypefaceUtil.getTypeface(THIN, context);
Typeface medium = TypefaceUtil.getTypeface(MEDIUM, context);
Map<String, Typeface> fonts = new HashMap<>();
fonts.put("sans-serif", regular);
fonts.put("sans-serif-light", light);
fonts.put("sans-serif-condensed", condensed);
fonts.put("sans-serif-thin", thin);
fonts.put("sans-serif-medium", medium);
TypefaceUtil.overrideFonts(fonts);

完整的示例检查

这仅适用于Android SDK 21及更高版本(对于较早的版本),请查看完整示例


5

只需使用此lib在您的成绩文件中编译即可

complie'me.anwarshahriar:calligrapher:1.0'

并在主要活动的onCreate方法中使用它

Calligrapher calligrapher = new Calligrapher(this);
calligrapher.setFont(this, "yourCustomFontHere.ttf", true);

这是最优雅的超快速方式。


2

这是我的项目的工作,来源 https://gist.github.com/artem-zinnatullin/7749076

在资源文件夹中创建字体目录,然后将自定义字体复制到字体目录,例如,我正在使用trebuchet.ttf;

创建一个类TypefaceUtil.java;

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

import java.lang.reflect.Field;
public class TypefaceUtil {

    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) {

        }
    }
}

在styles.xml中编辑主题,在下面添加

<item name="android:typeface">serif</item>

我的styles.xml中的示例

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:typeface">serif</item><!-- Add here -->
    </style>


    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        <item name="android:windowActionBarOverlay">true</item>
        <item name="android:windowFullscreen">true</item>
    </style>
</resources>

最后,在Activity或Fragment onCreate中调用TypefaceUtil.java

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TypefaceUtil.overrideFont(getContext(), "SERIF", "fonts/trebuchet.ttf");
    }

0

Android并没有提供太多支持在整个应用程序中应用字体的方式(请参阅本期)。您有4个选项来设置整个应用程序的字体:

  • 选项1:应用反射更改系统字体
  • 选项2:为每个需要自定义字体的视图创建和子类化自定义视图类
  • 选项3:实现一个视图爬网程序,该爬网程序遍历当前屏幕的视图层次结构
  • 选项4:使用第三方库。

这些选项的详细信息可以在这里找到。


0

我知道这个问题已经很老了,但是我找到了一个不错的解决方案。基本上,您将容器布局传递给此函数,它将把字体应用于所有受支持的视图,并在子布局中递归cicle:

public static void setFont(ViewGroup layout)
{
    final int childcount = layout.getChildCount();
    for (int i = 0; i < childcount; i++)
    {
        // Get the view
        View v = layout.getChildAt(i);

        // Apply the font to a possible TextView
        try {
            ((TextView) v).setTypeface(MY_CUSTOM_FONT);
            continue;
        }
        catch (Exception e) { }

        // Apply the font to a possible EditText
        try {
            ((TextView) v).setTypeface(MY_CUSTOM_FONT);
            continue;
        }
        catch (Exception e) { }

        // Recursively cicle into a possible child layout
        try {
            ViewGroup vg = (ViewGroup) v;
            Utility.setFont(vg);
            continue;
        }
        catch (Exception e) { }
    }
}

0

APP的只是一套字体到normalsansserifmonospace(而不是一个自定义的字体!),你可以做到这一点。

定义主题并将android:typeface属性设置为要在以下字体中使用的字体styles.xml

<resources>

    <!-- custom normal activity theme -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <!-- other elements -->
        <item name="android:typeface">monospace</item>
    </style>

</resources>

将主题应用于AndroidManifest.xml文件中的整个应用程序:

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application
        android:theme="@style/AppTheme" >
    </application>
</manifest>

android参考


您确定可行吗?根据Android文档:“必须为以下常量值之一:normal,sans,serif,monospace”。
tomrozb '16

1
哦,我知道...您是对的...我毕竟不明白这个问题:x我只想让我的整个应用使用等宽字体(不是自定义字体),并且看到它可以正常工作,所以我发布了此信息在这里.........我想我的回答对其他想要做类似事情的人仍然有用....所以我将其编辑并保留在这里.....我可以吗累积下来的选票。感谢您指出
Eric

嘿@Dave Cruise,它仅适用于等宽空间吗?我只测试了它的等宽线……而没有别的……。所以我不确定……但是根据文档,它也应该适用于“正常”,“ sans”和“ serif”。 .i认为字体比字体更通用,因此我们不能使用它将应用程序的字体设置为特定的字体,例如“ consolas”或类似的字体。
埃里克

@Eric是的。我也不知道 等宽的工作就像一种魅力,但对于正常的,无衬线的或无衬线的却没有运气。
戴夫·克鲁斯


-7

答案是否定的,你不能。请参见是否可以为整个应用程序设置自定义字体? 想要查询更多的信息。

有解决方法,但是“这里的一行代码和我所有的字体都将是这个而不是那个 ”。

(为此我感谢Google和Apple)。自定义字体占有一席之地,但是使它们易于在应用程序范围内替换,将创造出Comic Sans应用程序的整个世界)


41
完全不同意您的评论。全局设置字体应该很简单,而不是需要所需的变通办法。避免“ Comic Sans”应用程序由世界各地的开发人员/设计师来决定,而不是由Google / Apple来实施。
LocalPCGuy 2014年

4
一致性>精美的设计。
Martin Marconcini 2014年

14
但是,一致性<功能。我们开发了显示圣经希伯来语的应用程序。在Android设备上找到的所有普通字体(包括最新的Android L字体)都在渲染悬垂标记方面做得很糟糕(就此而言,它们在元音标记上的表现平庸,尽管它们越来越好了)。我们绝对需要在整个应用程序中使用自定义字体,而且我们不得不编写太多代码,只是为了使用它来获取所有必需的视图。
泰德·霍普
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.