如何在 XML 中为字体使用指定的权重

Posted

技术标签:

【中文标题】如何在 XML 中为字体使用指定的权重【英文标题】:How to use specified weights for fonts in XML 【发布时间】:2018-03-17 07:15:55 【问题描述】:

使用Fonts in XML 功能,您可以为字体系列指定各种字体粗细。例如:

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android"
             xmlns:app="http://schemas.android.com/apk/res-auto">

    <font android:font="@font/archivo_narrow_regular" android:fontWeight="400" android:fontStyle="normal"
        app:font="@font/archivo_narrow_regular" app:fontWeight="400" app:fontStyle="normal"/>

    <font android:font="@font/archivo_narrow_regular_italic" android:fontWeight="400" android:fontStyle="italic"
        app:font="@font/archivo_narrow_regular_italic" app:fontWeight="400" app:fontStyle="italic"/>

    <font android:font="@font/archivo_narrow_medium" android:fontWeight="500" android:fontStyle="normal"
        app:font="@font/archivo_narrow_medium" app:fontWeight="500" app:fontStyle="normal"/>

    <font android:font="@font/archivo_narrow_medium_italic" android:fontWeight="500" android:fontStyle="italic"
        app:font="@font/archivo_narrow_medium_italic" app:fontWeight="500" app:fontStyle="italic"/>

    <font android:font="@font/archivo_narrow_semibold" android:fontWeight="600" android:fontStyle="normal"
        app:font="@font/archivo_narrow_semibold" app:fontWeight="600" app:fontStyle="normal"/>

    <font android:font="@font/archivo_narrow_semibold_italic" android:fontWeight="600" android:fontStyle="italic"
        app:font="@font/archivo_narrow_semibold_italic" app:fontWeight="600" app:fontStyle="italic"/>

    <font android:font="@font/archivo_narrow_bold" android:fontWeight="700" android:fontStyle="normal"
        app:font="@font/archivo_narrow_bold" app:fontWeight="700" app:fontStyle="normal"/>

    <font android:font="@font/archivo_narrow_bold_italic" android:fontWeight="700" android:fontStyle="italic"
        app:font="@font/archivo_narrow_bold_italic" app:fontWeight="700" app:fontStyle="italic"/>

</font-family>

但我不知道如何实际使用这些权重;在 XML(布局/样式)文件或 Java 代码中。它们没有可用于TextViewfontWeight 属性,并且从ResourcesCompat.getFont(context, R.font.archivo_narrow) 创建的Typeface 对象没有提及字体粗细。

我意识到我可以只指定特定的字体资源(即R.font.archivo_narrow_semibold),但是在font-family 中具有fontWeight 属性有什么意义呢?


更新

在 API 级别 28 中添加了一个新的静态 create(Typeface family, int weight, boolean italic) 方法,以及一个 getWeight() 实例方法。这最终使得在 Java 代码中使用 fontWeight 属性成为可能;虽然仅适用于 API 级别 28 及更高版本,但我在支持库中没有找到任何类似物。

这很有用 - 并且表明 fontWeight 属性在过去没有任何用途 - 但我真的希望能够在 XML 样式中使用权重。

【问题讨论】:

我看到了问题中的更新,但我认为它实际上应该是一个答案,因为它对实际问题的回答比任何当前答案都要好。 28以下,字体粗细用于区分常规和粗体。 您尝试过textFontWeight XML 属性吗?即使在 API 28 上也不适合我。 【参考方案1】:

它看起来像 android 遵循 web 标准的字体管理和 android 应用程序的大小。

“font-weight”属性用于定义字体的粗细,例如常规或粗体。

但对于所有其他权重,使用从 100 到 900 的数字范围。 Web 字体的挑战之一是大多数 Web 浏览器不能正确支持除普通和粗体之外的字体粗细。下表描述了权重到数字定义的可能映射:

100    Extra Light or Ultra Light
200    Light or Thin
300    Book or Demi
400    Normal or Regular
500    Medium
600    Semibold, Demibold
700    Bold
800    Black, Extra Bold or Heavy
900    Extra Black, Fat, Poster or Ultra Black

你可以阅读更多关于字体粗细here


cc_montserrat_bold.xml

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <font
        android:font="@font/montserrat_bold"
        android:fontStyle="normal"
        android:fontWeight="700"
        app:font="@font/montserrat_bold"
        app:fontStyle="normal"
        app:fontWeight="700" />
    <font
        android:font="@font/montserrat_bolditalic"
        android:fontStyle="italic"
        android:fontWeight="700"
        app:font="@font/montserrat_bolditalic"
        app:fontStyle="italic"
        app:fontWeight="700" />

</font-family>

cc_montserrat_regular.xml

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <font
        android:font="@font/montserrat_regular"
        android:fontStyle="normal"
        android:fontWeight="400"
        app:font="@font/montserrat_regular"
        app:fontStyle="normal"
        app:fontWeight="400" />
    <font
        android:font="@font/montserrat_italic"
        android:fontStyle="italic"
        android:fontWeight="400"
        app:font="@font/montserrat_italic"
        app:fontStyle="italic"
        app:fontWeight="400" />


</font-family>

Kotlin 用法:

val textView = dialog.findViewById<TextView>(android.R.id.message) as TextView
val typeface = ResourcesCompat.getFont(context,R.font.cc_montserrat_regular)
        textView.typeface = typeface

Android 项目截图:

【讨论】:

是的,但是我该如何使用各种字体粗细? 我可以在&lt;font&gt; 标记中指定font-weight 属性,但我无法在我的代码中的任何其他位置引用font-weight 属性(即我可以设置权重,我只是不能使用权重)。有textStyle 属性,但只能指定bolditalicbold|italic。例如,没有semibold 这似乎有点矫枉过正。 font-family 通常包含所有变体,而不仅仅是特定权重的 normalitalic 变体。它仍然无法解释为什么有一个我无法使用的font-weight 属性 @Bryan,我已经浪费了好几个小时试图找到这个非常简单问题的答案。不知道为什么每个人都在建议荒谬的变通办法。你找到解决方案了吗? 疯了,仍然没有很好的兼容解决方案,疯了,这个作为答案发布的问题的可怕改写得到了 50 多票【参考方案2】:

正如@FlorianWalther 所指出的,TextView.textFontWeight 属性正是我想要的。这个属性显然是在 API 级别 28 中添加的,但 was not documented until recently。

确保所有权重都在同一个 XML 文件中(如我的问题所示),然后只需使用该属性和 fontFamily 属性即可。

<TextView android:id="@+id/weightedTextView"
    android:layout_
    android:layout_
    android:fontFamily="@font/archivo_narrow"
    android:textFontWeight="700"/>

据我所知,此属性仅在 API 级别 28 及以上版本中可用,如果我在支持库中找到它的对应项,我会更新。

【讨论】:

反向移植相关问题textFontWeight:issuetracker.google.com/issues/145311058 相关问题实际上包含指向旧 Android 版本的实现的链接。【参考方案3】:

Florian 在 cmets 中关于

Android 似乎忽略了字体系列中的所有内容,除了字体粗细 700 和 400,它分别用于粗体和非粗体 textStyles。

就是这样。您可以使用常规 400/700 和斜体 400/700。其他定义似乎都没有被使用,只有使用较新的 API,您才能真正用它们做任何事情。如果我遗漏了什么,请告诉我,但这似乎是您可以在较低 API 上控制的所有内容 - 粗体与否。


系统似乎确实在寻找替代权重,因此如果您指定 bold 但您没有定义任何重量 700 它将拉另一个权重(甚至是斜体变体),但您实际上不能说“为这种样式使用 Medium 500” - 您必须创建一个单独的字体系列并明确使用它,此时您不妨指定而是实际的字体?


为了完整起见,我已经完成了多个字体系列的事情(我使用的每个粗细都有一个单独的字体 - 常规、中等等)并将它们应用到由 Material Design type scale generator 生成的 styles 中。类型比例使用不同的权重,例如 light 用于 Headline1medium 用于 Subtitle2 但显然 Android 没有使用它们(它们也没有在样式层次结构中指定)。

因此,您可以通过将字体系列引用添加到生成的样式中来解决此问题:

<style name="TextAppearance.MdcTypographyStyles.Headline1" parent="TextAppearance.MaterialComponents.Headline1">
    <item name="fontFamily">@font/my_font_weight_light</item>
    <item name="android:fontFamily">@font/my_font_weight_light</item>
    <item name="android:textSize">123sp</item>
    <item name="android:letterSpacing">-0.0122</item>
</style>

其中my_font_weight_light.xml 是一个字体系列,仅包含字体的light 变体

<font-family xmlns:app="http://schemas.android.com/apk/res-auto">
    <font
        app:font="@font/my_font_light_italic"
        app:fontStyle="italic"
        app:fontWeight="400" />
    <font
        app:font="@font/my_font_light"
        app:fontStyle="normal"
        app:fontWeight="400" />
</font-family>

重量是错误的,400regular,但我认为如果 Android 无论如何只使用 400 来表示非粗体文本,那么如果我只是给它,它做奇怪事情的可能性就会更小它期望的价值,所以它不必去寻找替代品(也许选择斜体)。无论如何,“权重”是由我应用于样式的字体系列定义的。我没有费心添加 bold,因为样式使用固定的权重,而且我也没有使用粗体。

(edit - Jimit Patel 在 cmets 中提到,在一种情况下这对他们不起作用,并且使用粗体字体需要指定 700 的权重以让它在不同的 API 中保持一致。所以也许正确的权重很重要 - 或者至少选择 400700 中最接近它的一个。我不能花时间测试所有这些,所以我只是把它放在那里!)


下一个有趣的事情是,如果您通过设置fontFamily 属性将字体系列应用到整个应用程序,that will override any fontFamily settings you apply through textAppearance 因为主题样式优先于textAppearance。因此,您的“加权”样式将失去其“权重”,因为 fontFamily 将恢复为具有 常规 400 值的普通版本。

要解决这个问题,您必须将样式应用为样式,而不是 textAppearance,即:

style="@style/TextAppearance.MdcTypographyStyles.Headline1"

好玩!!

【讨论】:

表达得很好。我还有一个观察要补充。如果我在 bold TTF 字体文件 上使用 fontWeight="400",它在不同的 Android API 版本上会表现得很奇怪,如果我使用 fontWeight="700",那么它会完全按预期工作。 是否将textStyle(当您实际使用字体时,例如当您设置TextView 时)设置为normalbold?如果它是bold,那么我会有点期待,因为这基本上是说“寻找重量 700”,如果你的字体中没有定义它可能会变得很奇怪。这种hacky方法基本上是为每个权重创建一个新字体,并将它们全部视为regular for textStyle - 所以如果你想要粗体,你需要使用任何具有中等/半粗体/粗体变体的字体 如果即使使用 regularnormal 或任何 textStyle 值仍然很奇怪,请告诉我,我会在答案中添加注释! 没有使用特殊属性使其变为粗体。我使用粗体字体是为了让所有东西都符合品牌,但这是在不同设备上测试相同的TextView 时发现的。您可以针对 API 21 到 29 对其进行测试,对我来说,21、22 和 29 工作得很好,其余的都给出了额外的粗体。检查 2 或 3 个不同的 TTF 以获得更准确的观察结果。 Hrm 好的,我自己还没有看到(主要看 API 24、29 和 30),但也许我只是没有注意到,或者它也可能与字体相关,或者支持库版本...我将添加一条注释,告诉人们检查它是否有效,如果无效,请尝试不同的权重,无论如何我的 400 想法只是一个猜测。谢谢!【参考方案4】:

由于textFontWeight 属性是 API 级别 28 和更高级别,支持旧设备的解决方法是为每个字体粗细创建单独的 fontFamily 并从视图中引用 fontFamily。

res/layout/your_layout.xml

<TextView
    ...
    android:fontFamily="@font/fontFamily_your_font_demibold 
/>

res/font/fontFamily_your_font_demibold.xml

<font-family xmlns:app="http://schemas.android.com/apk/res-auto">

    <font
        app:font="@font/your_font_demibold"
        app:fontStyle="normal"
        app:fontWeight="600" />

</font-family>

res/font/fontFamily_your_font_bold.xml

<font-family xmlns:app="http://schemas.android.com/apk/res-auto">

    <font
        app:font="@font/your_font_bold"
        app:fontStyle="normal"
        app:fontWeight="800" />

</font-family>

【讨论】:

fontfamily 在这种情况下是没有用的,直接使用 textview 中的字体会更好【参考方案5】:

我在字体的几种粗细上苦苦挣扎:粗体、半粗体、中等、常规。 对我来说,当我为每个重量创建一个 .xml 文件时,它终于起作用了,正常和斜体,然后在布局或样式中使用 android:fontFamily:fontFamily: 引用它们。后者很重要,否则它只能在非常高的 API 级别下工作。

    <font-family xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">


    <font android:font="@font/internal_inter_bold" 
        android:fontStyle="normal"
        android:fontWeight="700"
        app:font="@font/internal_inter_bold"
        app:fontStyle="normal"
        app:fontWeight="700" />
    <font android:font="@font/internal_inter_bold_italic"
        android:fontStyle="italic"
        android:fontWeight="700"
        app:font="@font/internal_inter_bold_italic"
        app:fontStyle="italic"
        app:fontWeight="700" />
     </font-family>



     <style name="numbers_large">
        <item name="android:textSize">32sp</item>
        <item name="android:fontFamily">@font/inter_bold</item>
        <item name="fontFamily">@font/inter_bold</item>
    </style>

即使在 Android 5.0 中也可以使用,但未针对较低版本进行测试。

所以基本上为每个字体粗细创建一个 font.xml 文件,同时使用 app: 和 android: 前缀,然后用两个前缀引用它们。

【讨论】:

【参考方案6】:

编辑:这不是请求的解决方案:/

我找到了 Typeface.Builder 类,我认为这是您想要的。不幸的是,它仅适用于 API 级别 26 及更高级别。也许很快就会出现兼容库。

https://developer.android.com/reference/android/graphics/Typeface.Builder.html

 Typeface.Builder buidler = new Typeface.Builder("your_font_file.ttf");
 builder.setFontVariationSettings("'wght' 700, 'slnt' 20, 'ital' 1");
 builder.setWeight(700);  // Tell the system that this is a bold font.
 builder.setItalic(true);  // Tell the system that this is an italic style font.
 Typeface typeface = builder.build();

【讨论】:

不行,很遗憾只能通过Typeface.Builder设置权重;仍然无法通过创建的Typeface 引用该权重。 是的,对不起,我找到了一个权重输入,在没有完全理解的情况下感到兴奋。 - 我发现你的 *** 试图自己弄清楚同样的事情。在浏览了源代码之后,我只能发现,如果您引用一个字体系列,如果您将其指定为文本样式,它将尽最大努力获得最接近粗体(700)的粗细,否则它将找到最接近 400 . 没有办法要求你想要什么重量。希望他们尽快把它放进去,我在大多数设计中都使用半粗体作为我的标题权重,输入权重非常有用。【参考方案7】:

如何在 android studio 中使用不同字体的权重

    打开app/src/main/res/layout/you_awesome_layout.xml 选择Design tab 在“组件树”面板中,打开TextView 并选择右侧菜单底部的View all attributes 在“属性”面板中,打开fontFamily 下拉菜单并选择More Fonts… 选择家庭YouFontFamilyName 选择款式Regular/Bold/Semibold/Black/WhateverStyleYouHaveThere

瞧,我认为这是实现您想要的唯一方法

【讨论】:

我的自定义字体中出现的样式不能超过两种(例如,只有 BoldBold Italic 出现)。对于可用的 Google 字体(在 Downloadable 标题下)可以有更多样式;例如 Advent Pro 有 Thin、ExtraLight、Light、Regular、Medium、SemiBold 和 Bold。关于如何使用自定义字体模仿此功能的任何想法?【参考方案8】:

有关字体粗细值,请参阅 Android 官方参考:

android:fontWeight

整数。字体的粗细。当字体加载到字体堆栈中并覆盖字体标题表中的任何粗细信息时使用此属性。 属性值必须是正数、100 的倍数,并且介于 100 和 900 之间(含)。如果您不指定属性,则应用会使用字体标题表中的值。最常见的值是 400 表示常规重量,700 表示粗体。

https://developer.android.com/guide/topics/resources/font-resource

【讨论】:

【参考方案9】:

第 1 步:查找或下载您的字体,比如 cavier_dream

第二步:右键res文件夹,在res文件夹内创建字体资源文件夹

第 3 步:右键单击字体文件夹并创建一个字体资源文件,比如说 app_font.xml

第四步:打开app_font.xml文件,修改如下

<?xml version="1.0" encoding="utf-8"?>

<font
    android:font="@font/cavier_dream"
    android:fontWeight="400"
    android:fontStyle="normal"
    app:fontWeight="400"
    app:fontStyle="normal"
    app:font="@font/cavier_dream"/>

用法:

要在应用程序中全局使用,请转到 styles.xml 并在主题内创建一个新项目,如下所示

 <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- 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/app_font</item>
</style>

对于本地使用,只需使用 fontFamily 属性并将 app_font 设置为值。

编码愉快:)

【讨论】:

这确实有效,但我认为这可能会产生误导,因为当您真正想要设置 fontStyle/fontWeight 时,您必须设置 fontFamily。

以上是关于如何在 XML 中为字体使用指定的权重的主要内容,如果未能解决你的问题,请参考以下文章

如何在基于xml的spring配置中为hibernate.javax.cache.uri属性指定相对路径

如何在 Eclipse 中为所有文本编辑器更改字体大小?

如何在XML中为视图指定宽度和高度的百分比?

如何在多个标签问题中为 tensorflow 模型设置类权重?

如何在 scikit-learn 中为 OneVsRestClassifier 设置类权重?

如何在 Directwrite 中为给定字体获取可用的 OpenType 功能?