字体

编辑页面

了解如何使用本地文件或 Google 字体包将自定义字体集成到你的应用中


For the complete documentation index, see llms.txt. Use this Use this file to discover all available pages.

Android 和 iOS 自带各自的平台字体。为了提供一致的用户体验并增强应用的品牌形象,你可以使用自定义字体。

本指南介绍了将自定义字体添加并加载到项目中的不同方式,也提供了与字体相关的其他信息。

添加自定义字体

你可以通过两种方式将自定义字体添加到项目中:

  • 将字体文件添加到本地资源中。例如,放在 assets/fonts 目录下的字体文件。
  • 安装 Google Font 包。例如,安装 @expo-google-fonts/inter 包。

支持的字体格式

Expo SDK 官方支持在 Android、iOS 和 web 平台上使用 OTF 和 TTF 字体格式。如果你的字体是其他格式,则需要进行高级配置才能在项目中支持该格式。

可变字体

可变字体(包括 OTF 和 TTF 中的可变字体实现)并非在所有平台上都受支持。若要实现完整的平台支持,请使用静态字体。或者,你也可以使用类似 fontTools 的工具,从可变字体中提取你想使用的特定轴配置,并将其保存为单独的字体文件。

如何在 OTF 和 TTF 之间选择

如果你使用的字体同时有 OTF 和 TTF 版本,优先选择 OTF。.otf 文件比 .ttf 文件更小。有时,在某些场景下 OTF 的渲染效果也会稍好一些。

使用本地字体文件

将文件复制到项目的 assets/fonts 目录中。

assets/fonts 目录路径是在 React Native 应用中放置字体文件的一种常见约定。如果你遵循自定义约定,也可以把这些文件放在其他位置。

在项目中使用本地字体文件有两种方式:

  • 使用 expo-font 配置插件 将字体文件嵌入(仅 Android 和 iOS)。
  • 在运行时使用 useFonts hook 加载字体文件(Android、iOS 和 web)。

使用 expo-font 配置插件

expo-font 配置插件允许将一个或多个字体文件嵌入到项目的原生代码中。它支持 Android 和 iOS 的 ttfotf,而 woffwoff2 仅在 iOS 上受支持。

Note: 配置插件仅在原生平台(Android 和 iOS)上运行。对于 web,请改用 useFonts hook

由于以下优点,这是向应用添加字体的推荐方式:

  • 应用在设备上启动时,字体即可立即可用。
  • 应用启动时无需额外代码来异步加载字体。
  • 由于字体被打包进应用,因此在所有安装了该应用的设备上都能一致地使用字体。

不过,这种方式也有一些限制:

要将字体嵌入项目,请按以下步骤操作:

1

在项目中添加自定义字体文件后,安装 expo-font 库。

Terminal
npx expo install expo-font

2

将配置插件添加到你的 app config 文件中。配置必须使用 fontsandroidios 属性包含字体文件路径,这些属性接受一个或多个字体定义的数组。每个字体文件的路径相对于项目根目录。

下面的示例展示了字体可指定的所有有效方式:可以是一个包含 fontFamily 和其他属性的对象数组,也可以是一个字体文件路径数组。

对于 Android,你可以指定 fontFamilyweight,以及可选的 style(默认为 "normal"),这样字体会被嵌入为原生 XML resources。如果你在数组中只提供字体文件路径,那么文件名会成为 Android 上的字体族名称。iOS 总是从字体文件本身提取字体族名称。

如果你计划只使用 fontFamily 来引用字体,请提供字体路径数组(如下方的 FiraSans-MediumItalic.ttf 所示),并遵循我们关于如何确定要使用哪个字体族名称的建议。

如果你想通过 fontFamilyweightstyle 的组合来引用字体,请提供对象数组(如下方的 Inter 所示)。

app.json
{ "expo": { "plugins": [ [ "expo-font", { "fonts": [ "./assets/fonts/FiraSans-MediumItalic.ttf" ], "android": { "fonts": [ { "fontFamily": "Inter", "fontDefinitions": [ { "path": "./assets/fonts/Inter-BoldItalic.ttf", "weight": 700, "style": "italic" }, { "path": "./assets/fonts/Inter-Bold.ttf", "weight": 700 } ] } ] }, "ios": { "fonts": ["./assets/fonts/Inter-Bold.ttf", "./assets/fonts/Inter-BoldItalic.ttf"] } } ] ] } }

3

使用配置插件嵌入字体后,创建一个新的开发构建,并将其安装到你的设备、Android 模拟器或 iOS 模拟器上。

你可以通过指定 fontFamily 样式属性在 <Text> 中使用该字体。下面的示例与上面配置中定义的字体相对应。

<Text style={{ fontFamily: 'Inter', fontWeight: '700' }}>Inter Bold</Text> <Text style={{ fontFamily: 'Inter', fontWeight: '700', fontStyle: 'italic' }}>Inter Bold Italic</Text> <Text style={{ fontFamily: 'FiraSans-MediumItalic' }}>Fira Sans Medium Italic</Text>
在现有 React Native 项目中使用这种方式?

如何确定要使用哪个字体族名称

  • 如果你将字体以文件路径数组的形式提供(如上所述),在 Android 上,文件名(不含扩展名)会成为字体族名称。在 iOS 上,字体族名称会从字体文件本身读取。我们建议将字体文件命名为与其 PostScript 名称相同,以便两个平台上的字体族名称保持一致。

  • 如果你使用对象语法,请提供 “Family Name”。你可以在 macOS 的 Font Book 应用、fontdrop.info 或其他程序中找到它。

字体文件的 PostScript 名称是什么?

字体文件的 PostScript 名称 是按照 Adobe 的 PostScript 标准分配给字体的唯一标识符。操作系统和应用使用它来引用该字体。它不是字体的 显示名称

例如,Inter Black 字体文件的 PostScript 名称是 Inter-Black

Font Book app 在 macOS 上的截图。

使用 useFonts hook

expo-font 库中的 useFonts hook 允许异步加载字体文件。这个 hook 会跟踪加载状态,并在应用初始化时加载字体。

它适用于所有 Expo SDK 版本以及 Expo Go。要在项目中使用 useFonts hook 加载字体,请按以下步骤操作:

1

在项目中添加自定义字体文件后,安装 expo-fontexpo-splash-screen 库。

Terminal
npx expo install expo-font expo-splash-screen

expo-splash-screen 库提供了 SplashScreen 组件,你可以用它在字体加载完成之前阻止应用渲染。

2

在项目中的顶层组件中,例如根布局(src/app/_layout.tsx)文件,使用 useFonts hook 映射字体文件:

src/app/_layout.tsx
import { useFonts } from 'expo-font'; import * as SplashScreen from 'expo-splash-screen'; import {useEffect} from 'react'; SplashScreen.preventAutoHideAsync(); export default function RootLayout() { const [loaded, error] = useFonts({ 'Inter-Black': require('./assets/fonts/Inter-Black.otf'), }); useEffect(() => { if (loaded || error) { SplashScreen.hideAsync(); } }, [loaded, error]); if (!loaded && !error) { return null; } return ( %%placeholder-start%%... %%placeholder-end%% ) }

3

在 React 组件中通过 fontFamily 样式属性在 <Text> 上使用该字体:

<Text style={{ fontFamily: 'Inter-Black' }}>Inter Black</Text>

使用 Google Fonts

Expo 对 Google Fonts 中列出的所有字体提供一流支持。它们可通过 @expo-google-fonts 库使用。使用该库中的任意字体包,你都可以快速集成该字体及其变体。

在项目中使用 Google Font 有两种方式:

使用 expo-font 配置插件

注意: 使用 expo-font 配置插件嵌入 Google Font,与自行嵌入自定义字体具有相同的优点和限制。更多信息请参见使用 expo-font 配置插件加载本地字体文件

1

安装字体包。例如,要使用 Inter Black 字体,请使用下面的命令安装 @expo-google-fonts/inter 包。

Terminal
npx expo install expo-font @expo-google-fonts/inter

2

将配置插件添加到你的 app config 文件中。配置必须包含字体文件的路径,并使用 fonts 属性,该属性接受一个或多个字体文件组成的数组。字体文件路径是从 node_modules 目录中的字体包定义的。例如,如果你有一个名为 @expo-google-fonts/inter 的字体包,那么文件名就是 Inter_900Black.ttf

app.json
{ "plugins": [ [ "expo-font", { "fonts": ["node_modules/@expo-google-fonts/inter/900Black/Inter_900Black.ttf"] } ] ] }

3

通过配置插件嵌入字体后,创建一个新的开发构建,并将其安装到你的设备、Android 模拟器或 iOS 模拟器上。

在 Android 上,你可以使用字体文件名。例如,Inter_900Black。在 iOS 上,使用字体及其字重名称(PostScript 名称)。下面的示例演示了如何使用 Platform 为每个平台选择正确的字体族名称:

import { Platform } from 'react-native'; // 在 React 组件内部: <Text style={{ fontFamily: Platform.select({ android: 'Inter_900Black', ios: 'Inter-Black', }), }}> Inter Black </Text>

使用 useFonts hook

注意: 使用 useFonts hook 加载 Google Font,与自行嵌入自定义字体具有相同的优点和限制。更多信息请参见使用 useFonts hook 加载本地字体文件

每个 Google Fonts 包都提供了 useFonts hook 来异步加载字体。该 hook 会跟踪加载状态,并在应用初始化时加载字体。字体包还会导入字体文件,因此你无需显式导入它。

1

安装 Google Fonts 包、expo-fontexpo-splash-screen 库。

Terminal
npx expo install @expo-google-fonts/inter expo-font expo-splash-screen

expo-splash-screen 库提供了 SplashScreen 组件,你可以用它在字体加载完成之前阻止应用渲染。

2

安装字体包后,在项目中的顶层组件中使用 useFonts hook 映射字体,例如根布局(src/app/_layout.tsx)文件:

src/app/_layout.tsx
// 其余导入语句 import { Inter_900Black, useFonts } from '@expo-google-fonts/inter'; import * as SplashScreen from 'expo-splash-screen'; import {useEffect} from 'react'; SplashScreen.preventAutoHideAsync(); export default function RootLayout() { const [loaded, error] = useFonts({ Inter_900Black, }); useEffect(() => { if (loaded || error) { SplashScreen.hideAsync(); } }, [loaded, error]); if (!loaded && !error) { return null; } return ( %%placeholder-start%%... %%placeholder-end%% ) }

3

在 React 组件中,通过在 <Text> 上使用 fontFamily 样式属性来使用该字体:

<Text style={{ fontFamily: 'Inter_900Black' }}>Inter Black</Text>

附加信息

最小示例

expo-font 用法

请参阅 Expo Fonts API 参考中的用法部分,了解使用自定义字体的最小示例。

超出 OTF 和 TTF 之外的格式

如果你的字体格式不是 OTF 或 TTF,你必须自定义 Metro bundler 配置,将其作为额外资源包含进去,它才会生效。在某些情况下,渲染平台不支持的字体格式可能会导致你的应用崩溃。

作为参考,下表提供了在各个原生平台上可用的格式列表:

格式AndroidiOSWeb
bdf
dfont
eot
fon
otf
ps
svg
ttc
ttf
woff
woff2

平台内置字体

如果你不想通过指定 fontFamily 来使用自定义字体,那么将使用平台的默认字体。每个平台都有一组内置字体。在 Android 上,默认字体是 Roboto。在 iOS 上,是 SF Pro。

平台的默认字体通常都很易读。不过,如果系统默认字体被更改为另一种不易读的字体,也不必惊讶。在这种情况下,请使用你的自定义字体,这样你就可以精确控制用户将看到的内容。

处理 @expo/vector-icons 的首次加载

@expo/vector-icons 库中的图标第一次加载时,它们在你的应用中会显示为不可见图标。一旦加载完成,它们就会被缓存,供应用后续使用。为了避免在应用首次加载时显示不可见图标,请在初始加载界面期间使用 useFonts 进行预加载。例如:

src/app/_layout.tsx
import { useFonts } from 'expo-font'; import Ionicons from '@expo/vector-icons/Ionicons'; export default function RootLayout() { useFonts([require('./assets/fonts/Inter-Black.otf', Ionicons.font)]); return ( %%placeholder-start%%... %%placeholder-end%% ) }

现在,你可以在 React 组件中使用 Ionicons 库中的任意图标:

<Ionicons name="checkmark-circle" size={32} color="green" />
图标

了解如何在你的 Expo 应用中使用各种类型的图标,包括矢量图标、自定义图标字体、图标图片和图标按钮。

直接从网页加载远程字体

如果你正在加载远程字体,请确保它们是从已正确配置 CORS 的源提供的。如果你不这样做,你的远程字体在 web 平台上可能无法正常加载。

从本地资源加载字体是在应用中加载字体最安全的方式。将字体作为本地资源包含后,当你将应用提交到应用商店时,这些字体会与应用下载包一起打包,并可立即使用。你无需担心 CORS 或其他潜在问题。

不过,直接从网页加载字体文件的方法是将 require('./assets/fonts/FontName.otf') 替换为字体的 URL,如下面的示例所示。

使用远程字体
import { useFonts } from 'expo-font'; import { Text, View, StyleSheet } from 'react-native'; export default function App() { const [loaded, error] = useFonts({ 'Inter-SemiBoldItalic': 'https://rsms.me/inter/font-files/Inter-SemiBoldItalic.otf?v=3.12', }); if (!loaded || !error) { return null; } return ( <View style={styles.container}> <Text style={{ fontFamily: 'Inter-SemiBoldItalic', fontSize: 30 }}>Inter SemiBoldItalic</Text> <Text style={{ fontSize: 30 }}>平台默认字体</Text> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, });