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

84
使用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代码中。对于TextView,没有可用的fontWeight属性,从ResourcesCompat.getFont(context, R.font.archivo_narrow)创建的Typeface对象没有提到字重。

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


更新

在 API Level 28 中新增了一个静态的 create(Typeface family, int weight, boolean italic) 方法,以及一个 getWeight() 实例方法。这终于使得在 Java 代码中可以使用 fontWeight 属性;尽管只适用于 API Level 28 及以上版本,我没有在支持库中找到任何类似的功能。

这很有用,也表明过去的 fontWeight 属性没有任何作用,但我真的很想能够在 XML 样式中使用该权重。


1
我看到问题中的更新,但我认为它实际上应该是一个答案,因为它提供了比当前任何答案都更好的答案。 - arekolek
2
在28以下的区间,字体粗细用于区分普通和加粗。 - Florian Walther
1
你尝试过使用 textFontWeight XML 属性吗?即使在 API 28 上,它对我也不起作用。 - Florian Walther
11个回答

80

看起来Android在应用程序的字体管理和大小方面遵循Web标准。

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

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

100    Thin (Hairline)
200    Extra Light (Ultra Light)
300    Light
400    Normal (Regular)
500    Medium
600    Semi Bold (Demi Bold)
700    Bold
800    Extra Bold (Ultra Bold)
900    Black (Heavy)
950    Extra Black (Ultra Black)

您可以在此处了解有关字重的更多信息。


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 项目截图:

在此输入图片描述


28
好的,但是我该如何使用不同的字重呢? - Bryan
11
我可以在<font>标签中设定font-weight属性,但我找不到一种方法来在代码中其他位置引用该属性(即我可以设置字重,但无法使用该字重)。虽然有一个textStyle属性,但你只能指定bolditalicbold|italic,例如没有semibold - Bryan
8
这似乎有点过头了。font-family 通常包括所有变体,而不仅仅是特定字重的 normalitalic 变体。这仍然无法解释为什么有一个我无法使用font-weight 属性。 - Bryan
15
@Bryan,我浪费了数小时来寻找这个非常简单的问题的答案。不确定为什么每个人都建议荒谬的解决方案。你最终找到了解决方法吗? - Theo
5
很疯狂,现在仍然没有一个好的兼容解决方案,更疯狂的是,这个可怕的对问题重新表述的回答竟然获得了50多票。 - Nick Cardoso
显示剩余10条评论

32

正如@FlorianWalther所指出的那样,TextView.textFontWeight属性恰好是我在寻找的。该属性显然是在API级别28中添加的,但是直到最近才被记录在案中

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

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

据我所知,此属性仅在API级别28及以上可用。如果我找到了其在支持库中的对应项,我将进行更新。


7
与"回溯textFontWeight"相关的问题:https://issuetracker.google.com/issues/145311058 - Gaëtan
3
相关问题实际上包含了实现此功能在旧版Android上的链接。 - user3738870

22

Florian在评论中提到的是对的,就为了明确它(因为我花了很长时间来研究它的工作原理):

Android似乎忽略字体系列中除了700和400字重之外的所有内容,其中700和400字重分别用于粗体和非粗体textStyle

就是这样。您可以有常规的400/700,以及斜体的400/700。没有其他定义似乎被使用,只有在较新的API中才能实际使用它们。如果我漏掉了什么,请告诉我,但在较低的API上似乎只能控制粗体或非粗体。


系统似乎在寻找替代字重时会出现问题,因此如果您指定了bold但是没有定义任何字重为700的内容,则它将拉取另一个字重(甚至斜体变体),但实际上您无法说“在这种风格中使用 Medium 500 ”-您必须创建一个单独的字体系列并显式使用它,在那一点上,您可能会更愿意直接指定实际字体?
为了完整起见,我已经进行了多种字体族的处理(对于我使用的每个重量都有一个独立的字体族-常规、中等等),并在Material Design类型比例生成器生成的样式中应用它们。该类型比例使用不同的重量,如Headline1lightSubtitle2medium,但显然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是一个仅包含字体的变体的字体族

<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,因为样式使用固定的字重,而且我也没有使用粗体。

编辑- Jimit Patel 在评论中提到,在某些情况下,这对他们不起作用,并且使用粗体字需要指定一个权重为 700 的值才能在不同的 API 中保持一致。所以也许正确的字重很重要-或者至少选择最接近 400700 的字重。我没有时间测试所有这些,所以我只是把它放出来!)


下一个有趣的事情是,如果你通过设置主题的fontFamily属性将字体族应用于整个应用程序,那么它将覆盖你通过textAppearance应用的任何fontFamily设置,因为主题样式优先于textAppearance。所以你的“加重”样式将失去它们的“重量”,因为fontFamily将被设置回具有常规400值的普通版本。
要解决这个问题,你必须将你的样式作为样式而不是textAppearance应用,即:
style="@style/TextAppearance.MdcTypographyStyles.Headline1"

有趣!!


表达得很好。我还有一个观察要添加。如果我在粗体TTF字体文件上使用 fontWeight="400",它在不同的Android API版本上表现出奇怪的行为,而如果我使用 fontWeight="700",则它会按预期工作。 - Jimit Patel
这是使用“textStyle”(实际使用字体时,例如设置“TextView”时)设置为“normal”或“bold”吗?如果是“bold”,那么我会期望,因为它基本上表示“查找重量为700”,如果您的字体中没有定义,则可能会出现奇怪的情况。这种hacky方法基本上为每个权重创建一个新字体,并将它们全部视为“regular”用于“textStyle”-因此,如果您想要粗体,您需要使用具有中等/半粗体/粗体变体的任何字体。 - cactustictacs
如果即使使用“regular”或“normal”或任何“textStyle”值仍然感觉奇怪,请告诉我,我会在答案中添加注释! - cactustictacs
1
没有使用特殊属性来使其加粗。我使用粗体字体以使一切符合品牌要求,但在测试不同设备上的相同“TextView”时发现了这个问题。您可以在API 21到29上进行测试,对我而言,21、22和29都正常工作,其他版本则会出现过度加粗的情况。尝试使用2或3种不同的TTF文件以获得更准确的观察结果。 - Jimit Patel
1
好的,我自己没有看到过这种情况(主要是在API 24、29和30上查看),但也许我只是没有注意到,或者它可能与字体有关,或者支持库版本有关... 我会添加一个注释,告诉人们检查它是否有效,并尝试不同的字重,如果不行的话,我的400的想法只是一个猜测。谢谢! - cactustictacs
从API 27测试中得知:仅使用android:fontFamily来设置默认字体是有效的,而使用样式和属性为视图元素设置fontFamily则会覆盖它。如果按照当前的指南将半粗体字体添加到应用程序中,并设置特定字体,不要为样式或视图元素设置fontWeight,则可以获得例如半粗体字体。 - Henrik Erlandsson

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>

4
在这种情况下,fontfamily 是无用的,直接在 textview 中使用字体会更好。 - Magnas

3

我曾经遇到一些字体的重量问题:粗体、半粗体、中等、常规。 对我而言,最终的解决方案是为每种重量创建一个 .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:前缀,然后使用这两个前缀引用它们。


1

以下是在Android Studio中使用不同字体权重的方法:

  1. 打开 app/src/main/res/layout/you_awesome_layout.xml 文件
  2. 选择 Design 选项卡
  3. 在组件树面板中,展开你的 TextView 并选择右侧菜单底部的 View all attributes
  4. 在属性面板中,打开 fontFamily 下拉框并选择 More Fonts…
  5. 选择字体族 YouFontFamilyName
  6. 选择样式 Regular/Bold/Semibold/Black/WhateverStyleYouHaveThere

这样就可以实现你想要的效果了。


我无法让我的自定义字体显示超过两种样式(例如,只有“粗体”和“粗斜体”显示出来)。对于可用的 Google 字体(在“可下载”标题下),可能会有更多的样式;例如 Advent Pro 有 Thin、ExtraLight、Light、Regular、Medium、SemiBold 和 Bold。您有什么想法可以模仿这个功能与我的自定义字体? - Bryan

1

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

我找到了 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引用该字重。 - Bryan
1
是的,抱歉,我发现了一个权重输入并且兴奋地使用它,但并没有完全理解。- 我在寻找相同问题的答案时发现了你的StackOverflow页面。经过查看源代码,我发现如果您引用字体系列,它会尽最大努力获取最接近粗体(700)的字重,如果您将其指定为文本样式,否则它会找到最接近400的字重。没有办法请求您想要的字重。希望他们很快就能加入这个功能,因为在大多数设计中,我都使用半粗体作为我的标题字重,拥有字重输入将非常有用。 - kassim

0

该功能已经被移植到AndroidX Core 1.9.0-beta01,于2022年8月10日发布。因此,现在可在API 28以下使用。

移植了Typeface#create(Typeface, int, boolean),允许从字体系列中创建具有特定权重的字体(I342dc

https://developer.android.com/reference/androidx/core/graphics/TypefaceCompat#create(android.content.Context,android.graphics.Typeface,int,boolean)

Typeface family = ResourcesCompat.getFont(context, R.font.archivo_narrow);
int weight = 600;
boolean italic = false;
Typeface typeface = TypefaceCompat.create(context, family, weight, italic);
textView.setTypeface(typeface);

0

如果您的API级别低于28且不想创建2个XML,则可以使用此扩展:

@BindingAdapter("textFontWeight")
fun TextView.textFontWeight(int: Int) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        typeface = Typeface.create(typeface, int, false)
    }
}

使用方法如下:

    <TextView
    ...
    app:textFontWeight="@{700}"/>

-1

步骤 1:找到或下载您的字体,比如说cavier_dream。

步骤 2:右键单击“res”文件夹并在其中创建字体资源文件夹。

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

步骤 4:打开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。 - Marius Kohmann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接