字体

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


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

🌐 Android and iOS come with their own set of platform fonts. To provide a consistent user experience and enhance your app's branding, you can use custom fonts.

本指南介绍了向项目中添加和加载自定义字体的不同方法,还提供了与字体相关的其他信息。

🌐 This guide covers different ways you can add and load a custom font into your project and also provides additional information related to fonts.

添加自定义字体

🌐 Add a custom font

有两种方法可以将自定义字体添加到项目中:

🌐 There are two ways you can add a custom font into your project:

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

支持的字体格式

🌐 Supported font formats

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

🌐 Expo SDK officially supports OTF and TTF font formats across Android, iOS and web platforms. If your font is in another font format, you have to set up advanced configuration to support that format in your project.

可变字体

🌐 Variable fonts

可变字体,包括 OTF 和 TTF 中的可变字体实现,并不是所有平台都支持。要获得完整的平台支持,请使用静态字体。或者,可以使用诸如 fontTools 的工具,从可变字体中提取你想要使用的特定轴配置,并将其保存为一个单独的字体文件。

🌐 Variable fonts, including variable font implementations in OTF and TTF, do not have support across all platforms. For full platform support, use static fonts. Alternatively, use a utility such as fontTools to extract the specific axis configuration you want to use from the variable font and save it as a separate font file.

如何在 OTF 和 TTF 之间进行选择

🌐 How to choose between OTF and TTF

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

🌐 If the font you're using has both OTF and TTF versions, prefer OTF. The .otf files are smaller than .ttf files. Sometimes, OTF also renders slightly better in certain contexts.

使用本地字体文件

🌐 Use a local font file

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

🌐 Copy the file into your project's assets/fonts directory.

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

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

🌐 Two ways to use the local font file in your project:

  • 使用 expo-font 配置插件 嵌入字体文件(仅限 Android 和 iOS)。
  • 在运行时使用 useFonts 钩子加载字体文件(适用于 Android、iOS 和 Web)。

使用 expo-font 配置插件

🌐 With expo-font config plugin

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

🌐 The expo-font config plugin allows embedding one or more font files in your project's native code. It supports ttf and otf for both Android and iOS, and woff and woff2 are supported on iOS only.

注意: 配置插件仅在原生平台(Android 和 iOS)上运行。对于网页,请改用 useFonts 钩子

这是向你的应用添加字体的推荐方法,因为它具有以下优点:

🌐 This is the recommended method for adding fonts to your app due to its benefits:

  • 当应用在设备上启动时,字体立即可用。
  • 应用启动时,无需额外代码即可异步加载项目中的字体。
  • 由于字体已打包在应用中,因此它们在安装应用的所有设备上始终可用。

但是,这种方法也有一些限制:

🌐 However, this method also has some limitations:

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

🌐 To embed a font in a project, follow the steps below:

1

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

🌐 After adding a custom font file in your project, install the expo-font library.

Terminal
npx expo install expo-font

2

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

🌐 Add the config plugin to your app config file. The configuration must contain the path to the font file using fonts, android or ios properties which take an array of one or more font definitions. The path to each font file is relative to the project's root.

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

🌐 The example below showcases all valid ways a font can be specified: as an array of objects that specify fontFamily and other properties, or an array of paths to font files.

对于 Android,你可以指定 fontFamilyweight,以及可选的 style(默认为 "normal"),这将把字体嵌入为原生的 XML 资源。如果你仅在数组中提供字体文件路径,文件名将成为 Android 上的字体系列名称。iOS 总是从字体文件本身提取字体系列名称。

🌐 For Android, you can specify the fontFamily, weight, and optionally style (defaults to "normal"), which will embed the fonts as native XML resources. If you provide only the font file paths in an array, the file name becomes the font family name on Android. iOS always extracts the font family name from the font file itself.

如果你计划仅使用 fontFamily 来引用字体,请提供一个字体路径数组(见下文的 FiraSans-MediumItalic.ttf),并遵循我们的文件命名推荐

🌐 If you plan to refer to fonts using just the fontFamily, provide an array of font paths (see FiraSans-MediumItalic.ttf below) and follow our recommendation for file naming.

如果你想使用 fontFamilyweightstyle 的组合来引用字体,请提供一个对象数组(见下方的 Inter)。

🌐 If you want to refer to fonts using a combination of fontFamily, weight, and style, provide an array of objects (see Inter below).

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 模拟器上。

🌐 After embedding the font with the config plugin, create a new development build and install it on your device or Android Emulator or iOS Simulator.

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

🌐 You can use the font with <Text> by specifying the fontFamily style prop. The examples below correspond to the fonts defined in the configuration above.

<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 项目中使用这种方法?

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

🌐 How to determine which font family name to use

  • 如果你以文件路径数组的形式提供字体(如上所述),在 Android 上,文件名(不含扩展名)将成为字体家族名称。在 iOS 上,字体家族名称是从字体文件本身读取的。我们建议将字体文件命名为其 PostScript 名称,这样字体家族名称在两个平台上保持一致。
  • 如果你使用对象语法,请提供“字体家族名称”。可以在 macOS 的字体册应用、fontdrop.info 或其他程序中找到此信息。
字体文件的 PostScript 名称是什么?

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

🌐 The PostScript name of a font file is a unique identifier assigned to the font that follows Adobe's PostScript standard. It is used by operating systems and apps to refer to the font. It is not a font's display name.

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

🌐 For example, Inter Black font file's PostScript name is Inter-Black.

来自 macOS 上 Font Book 应用的截图.

🌐 Screenshot from Font Book app on macOS.

使用 useFonts 钩子

🌐 With useFonts hook

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

🌐 The useFonts hook from expo-font library allows loading the font file asynchronously. This hook keeps track of the loading state and loads the font when an app is initialized.

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

🌐 It works with all Expo SDK versions and with Expo Go. To load a font in a project using useFonts hook, follow the steps below:

1

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

🌐 After adding a custom font file in your project, install the expo-font and expo-splash-screen libraries.

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

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

🌐 The expo-splash-screen library provides SplashScreen component that you can use to prevent rendering the app until the font is loaded and ready.

2

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

🌐 Map the font file using the useFonts hook in a top level component such as the root layout (app/layout.tsx) file in your project:

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> 上使用该字体:

🌐 Use the font on the <Text> by using fontFamily style prop in a React component:

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

使用谷歌字体

🌐 Use Google Fonts

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

🌐 Expo has first-class support for all fonts listed in Google Fonts. They are available using @expo-google-fonts library. With any of the font package from this library, you can quickly integrate that font and its variants.

在项目中使用 Google 字体的两种方法:

🌐 Two ways to use a Google Font in your project:

使用 expo-font 配置插件

🌐 With expo-font config plugin

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

1

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

🌐 Install the font package. For example, to use Inter Black font, install the @expo-google-fonts/inter package with the command below.

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

2

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

🌐 Add the config plugin to your app config file. The configuration must contain the path to the font file using fonts property which takes an array of one or more font files. The path to the font file is defined from the font package inside the node_modules directory. For example, if you have a font package named @expo-google-fonts/inter, then the name of the file is Inter_900Black.ttf.

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

3

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

🌐 After embedding the font with the config plugin, create a new development build and install it on your device or Android Emulator or iOS Simulator.

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

🌐 On Android, you can use the font file name. For example, Inter_900Black. On iOS, use the font and its weight name (PostScript name). The example below demonstrates how to use Platform to select the correct font family name for each platform:

import { Platform } from 'react-native'; // Inside a React component: <Text style={{ fontFamily: Platform.select({ android: 'Inter_900Black', ios: 'Inter-Black', }), }}> Inter Black </Text>

使用 useFonts 钩子

🌐 With useFonts hook

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

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

🌐 Each google Fonts package provides the useFonts hook to load the fonts asynchronously. This hook keeps track of the loading state and loads the font when an app is initialized. The font package also imports the font file so you don't have to explicitly import it.

1

安装 Google 字体包,以及 expo-fontexpo-splash-screen 库。

🌐 Install the Google Fonts package, expo-font and expo-splash-screen libraries.

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

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

🌐 The expo-splash-screen library provides SplashScreen component that you can use to prevent rendering the app until the font is loaded and ready.

2

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

🌐 After installing the font package, map the font using the useFonts hook in a top level component such as the root layout (app/layout.tsx) file in your project:

app/_layout.tsx
// Rest of the import statements 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 组件中,通过使用 fontFamily 样式属性在 <Text> 上使用该字体:

🌐 Use the font on the <Text> by using fontFamily style prop in a React component:

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

附加信息

🌐 Additional information

最小的例子

🌐 Minimal example

expo-font 使用

See usage section in Expo Fonts API reference for a minimal example of using a custom font.

超越 OTF 和 TTF

🌐 Beyond OTF and TTF

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

🌐 If your font is in format other than OTF or TTF, you have to customize the Metro bundler configuration to include it as an extra asset for it to work. In some cases, rendering a font format that a platform doesn't support may cause your app to crash.

供参考,下表提供了在各本地平台上可用的列表格式:

🌐 For reference, the following table provides the list formats that work on each native platform:

格式安卓iOS网页
bdf
dfont
eot
fon
otf
ps
svg
ttc
ttf
woff
woff2

平台内置字体

🌐 Platform built-in fonts

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

🌐 If you don't want to use a custom font by specifying a fontFamily, platform's default font will be used. Each platform has a set of built in fonts. On Android, the default font is Roboto. On iOS, it's SF Pro.

一个平台的默认字体通常是易于阅读的。然而,当系统默认字体被更改为另一种不易阅读的字体时,不要感到惊讶。在这种情况下,使用你的自定义字体,这样你就可以精确控制用户将看到的内容。

🌐 A platform's default font is usually easy-to-read. However, don't be surprised when the system default font is changed to use another font that is not easy to read. In this case, use your custom font so you have precise control over what the user will see.

处理 @expo/vector-icons 初始加载

🌐 Handle @expo/vector-icons initial load

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

🌐 When the icons from @expo/vector-icons library load for the first time, they appear as invisible icons in your app. Once they load, they're cached for all the app's subsequent usage. To avoid showing invisible icons on your app's first load, preload during the initial loading screen with useFonts. For example:

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 库的任何图标:

🌐 Now, you can use any icon from the Ionicons library in a React component:

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

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

直接从网络加载远程字体

🌐 Loading a remote font directly from the web

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

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

🌐 Loading fonts from a local asset is the safest way to load a font in your app. When including fonts as local assets, after you submit your app to the app stores, these fonts are bundled with the app download and will be available immediately. You don't have to worry about CORS or other potential issues.

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

🌐 However, loading a font file directly from web is done by replacing the require('./assets/fonts/FontName.otf') with the URL of your font as shown in the example below.

Using a remote font
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 }}>Platform Default</Text> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, });