【问题标题】:How to set default font family for entire Android app如何为整个 Android 应用设置默认字体系列
【发布时间】:2013-04-30 13:36:30
【问题描述】:

我在我的应用中使用 Roboto 浅色字体。要设置字体,我必须将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>

【问题讨论】:

标签: android android-fonts


【解决方案1】:

答案是肯定的。

TextViewButton 类的 Global Roboto 灯:

<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 这样的内置字体,但这就是问题所在。 对于自定义字体(例如从资产加载),此方法不起作用。

编辑 08/13/15

如果您使用 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 必须包含它。

【讨论】:

  • 您从哪里获得sans-serif-light 值?某处是否有fontFamily 的有效值列表?我一直在查看文档以及 Android 源代码中的主题和样式文件,但找不到任何东西。
  • 这仅适用于 API 级别 16.. 名称“android:fontFamily”仅存在于级别 16 或更高级别.. 例如 API 14 有没有办法做到这一点?跨度>
  • @LorenzoBarbagli,您可以查看Calligraphy
  • 如果我有自定义字体怎么办?
  • 是的,我还想为整个应用程序添加自定义字体。我怎样才能做到这一点 ?。我是否需要按照第一个答案中的建议覆盖 TextView 并替换所有 TextView
【解决方案2】:

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

  1. 如果您有支持库 >=,请检查您的应用 build.gradle 26.0.0
  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了解更多详细信息。

【讨论】:

  • 当面向 API 26+ 时,这应该是可接受的方法。使用支持库时,只需去掉android:前缀
  • 如果你只使用无前缀版本,没关系。 API 将忽略前缀
  • 这不会在任何地方设置字体...例如如果您有派生自 Base.TextAppearance.AppCompat 的样式,则不会在此处使用。
  • @Ixx,如何也覆盖这些样式?
  • 记住在定位 api 时也要使用 AppCompatTextView
【解决方案3】:

要更改您的应用字体,请按照以下步骤操作:

  1. res 目录中创建一个新目录并将其命名为font
  2. 在字体文件夹中插入字体 .ttf/.otf,确保字体名称为小写字母和仅下划线。
  3. res 内 -> values -> styles.xml&lt;resources&gt; 内 -> &lt;style&gt; 添加你的字体&lt;item name="android:fontFamily"&gt;@font/font_name&lt;/item&gt;

现在您的所有应用文本都应该使用您添加的字体。

【讨论】:

  • 在使用自定义字体时如何添加粗体和常规字体?
  • 这仅适用于 API 级别 26 及以上,API 21 及以下如何?
  • 很好的答案,对于那些正在导入 otf 自定义字体的人来说非常有用且切中要害。
【解决方案4】:

阅读下面的更新

我在嵌入新字体时遇到了同样的问题,最后让它与扩展 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 元素更改为 from to。如果您在 Eclipse 中使用 UI-Creator,有时他不会正确显示 TextViews。是唯一对我有用的东西...

更新

现在我使用反射来更改整个应用程序中的字体而不扩展 TextViews。 Check out this SO post

更新 2

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

android:fontFamily="@font/embeddedfont"

更多信息:Fonts in XML

【讨论】:

  • 这不是解决方案。我正在使用许多不同的视图,而不仅仅是 TextView。我想设置一次字体并忘记它。此外,您的代码会为每个 TextView 创建新对象。至少将该字段声明为静态,以便从资源中加载字体一次。
  • ...嗯,有一个查找和替换功能,在这种情况下效果很好
  • 这行不通。当变量为静态时,您不能调用getContext()。您应该以类似单例的方式实现它,否则当前代码甚至无法编译。
  • 我恢复了上次提交。
  • @tomrozb :D 我刚刚意识到,我所做的最后一次快速更改是因为您的 cmets!积分够多了,欢迎大家自行优化代码示例。否则几年后我们仍然会谈论这个话题,那时没有人再关心智能手机了;)
【解决方案5】:

在你的 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”更改为您自己的字体名称..

【讨论】:

  • 我试过了,效果很好,但我想知道为什么人们使用书法库来代替?
  • @M.Muzammil calligraphy 是一个相当古老的库,甚至不再维护。通常人们使用它是因为他们已经使用了很长时间。发布书法时,这个答案中描述的解决方案是不可能的,因为字体资源是在2017年才引入的
【解决方案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);

对于片段,你可以做类似的事情。

【讨论】:

  • 听起来不错,但想知道如何让它在 recyclerView 内容中工作?
  • 我刚试过这个。太重而无法渲染。像地狱一样减速recyclerView
  • 完全不推荐用于任何列表视图,这个技巧只是为了节省编写静态视图的时间。
【解决方案7】:

只需使用这个库在你的成绩文件中编译它

complie'me.anwarshahriar:calligrapher:1.0'

并在主Activity的onCreate方法中使用

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

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

【讨论】:

    【解决方案8】:

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

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

    完整示例check

    这仅适用于 Android SDK 21 及更高版本,早期版本请查看完整示例

    【讨论】:

      【解决方案9】:

      在 Android Studio 中很容易做到。

      1. 在此方法中,您需要验证您的minsdkveriosn。它必须需要minsdkversion &gt;=16

      1. 在“res”文件夹中创建“font”文件夹。在 android studio 中新建 > 文件夹 > 字体文件夹。

      1. 将您的字体文件上传到该字体文件夹。

      1. 在您的 style.xml 文件中,在“基本应用程序主题”的样式下添加这一行。

        &lt;item name="android:fontFamily"&gt;@font/ubuntubold&lt;/item&gt;

      【讨论】:

        【解决方案10】:

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

        在 Asset Folder 中创建字体目录,然后将自定义字体复制到字体目录,例如我使用的是 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>
        

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

        【讨论】:

          【解决方案11】:

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

          • 选项1:应用反射改变系统字体
          • 选项 2:为每个需要自定义字体的 View 创建自定义 View 类并将其子类化
          • 选项3:实现一个遍历视图的视图爬虫 当前屏幕的层次结构
          • 选项 4:使用 3rd 方库。

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

          【讨论】:

            【解决方案12】:

            我知道这个问题已经很老了,但我找到了一个很好的解决方案。 基本上,你将容器布局传递给这个函数,它会将字体应用到所有支持的视图,并递归地在子布局中循环:

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

            【讨论】:

              【解决方案13】:

              只需将应用的字体设置为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 reference

              【讨论】:

              • 你确定这有效吗?根据 Android 文档:“必须是以下常量值之一:normal、sans、serif、monospace”。
              • 哦,我明白了……你说得对……我根本不明白这个问题:x 我只是想让我的整个应用程序使用等宽字体(不是自定义)和我看到它有效,所以我在这里发布了这个............我认为我的回答对于其他想要做类似事情的人仍然有用......所以我会编辑它并把它留在这里...... ...我很好是它积累了反对票。感谢您指出这一点
              • 嘿@Dave Cruise,它只适用于等宽空间吗?我只测试了等宽字体......没有别的......所以我不确定......但根据文档,它也应该适用于“正常”、“无”和“衬线”...... .我认为字体比字体更通用,所以我们不能用它来将应用程序的字体设置为特定的字体,比如“consolas”之类的。
              • @Eric 是的。我也不知道。等宽字体像魅力一样工作,但对于普通字体、无衬线字体或衬线字体来说就没有运气了。
              【解决方案14】:

              试试这个库,它轻量级且易于实现

              https://github.com/sunnag7/FontStyler

              <com.sunnag.fontstyler.FontStylerView
                            android:textStyle="bold"
                            android:text="@string/about_us"
                            android:layout_width="match_parent"
                            android:layout_height="match_parent"
                            android:paddingTop="8dp"
                            app:fontName="Lato-Bold"
                            android:textSize="18sp"
                            android:id="@+id/textView64" />
              

              【讨论】:

                【解决方案15】:

                这就是我们的做法:

                private static void OverrideDefaultFont(string defaultFontNameToOverride, string customFontFileNameInAssets, AssetManager assets)
                {
                    //Load custom Font from File                
                    Typeface customFontTypeface = Typeface.CreateFromAsset(assets, customFontFileNameInAssets);
                
                    //Get Fontface.Default Field by reflection
                    Class typeFaceClass = Class.ForName("android.graphics.Typeface");
                    Field defaultFontTypefaceField = typeFaceClass.GetField(defaultFontNameToOverride);
                
                    defaultFontTypefaceField.Accessible = true;
                    defaultFontTypefaceField.Set(null, customFontTypeface);
                }
                

                【讨论】:

                • 您能否解释一下您的答案与其他 14 个答案有何不同,以及它是如何工作的?
                • 这是什么语言?它看起来不像 Java,有小写的 string 和大写的方法,如 Class.ForName
                • 哦,它是 C#,因为这个项目使用 Xamarin。
                【解决方案16】:

                答案是否定的,你不能。 见Is it possible to set a custom font for entire of application? 了解更多信息。

                有一些变通方法,但是“这里只有一行代码,我所有的字体都将是 this 而不是 that”这行没有任何内容。

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

                【讨论】:

                • 完全不同意你的评论。全局设置字体应该是微不足道的,而不是需要所需的变通方法。避免使用“Comic Sans”应用程序取决于世界的开发人员/设计人员,而不是 Google/Apple 来强制执行。
                • 一致性 > 花式设计。
                • 然而,一致性
                猜你喜欢
                • 2014-02-09
                • 1970-01-01
                • 2012-02-01
                • 2021-10-07
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2019-09-27
                相关资源
                最近更新 更多