跳到主要内容

图片

静态图片资源

React Native 提供了一种统一的方式来管理 Android 和 iOS 应用中的图片及其他媒体资源。要将静态图片添加到应用中,请将其放置在源代码树中的某个位置并像这样引用它:

tsx
<Image source={require('./my-icon.png')} />

图片名称的解析方式与 JS 模块的解析方式相同。在上面的示例中,打包器将在需要该图片的组件所在的同一文件夹中查找 my-icon.png

你可以使用 @2x@3x 后缀来为不同的屏幕密度提供图片。如果你有以下文件结构:

.
├── button.js
└── img
├── check.png
├── check@2x.png
└── check@3x.png

...并且 button.js 代码包含:

tsx
<Image source={require('./img/check.png')} />

...打包器将捆绑并提供与设备屏幕密度相对应的图片。例如,check@2x.png 将在 iPhone 7 上使用,而 check@3x.png 将在 iPhone 7 Plus 或 Nexus 5 上使用。如果没有与屏幕密度匹配的图片,则会选择最接近的最佳选项。

在 Windows 上,如果你向项目中添加了新图片,可能需要重启打包器。

以下是一些你可以获得的好处:

  1. Android 和 iOS 上采用相同系统。
  2. 图片与 JavaScript 代码位于同一文件夹中。组件是自包含的。
  3. 没有全局命名空间,即你无需担心名称冲突。
  4. 只有实际使用的图片才会被打包到你的应用中。
  5. 添加和更改图片不需要重新编译应用,你可以像往常一样刷新模拟器。
  6. 打包器知道图片的尺寸,无需在代码中重复设置。
  7. 图片可以通过 npm 包分发。

为了使此功能正常工作,require 中的图片名称必须是静态已知的。

tsx
// GOOD
<Image source={require('./my-icon.png')} />;

// BAD
const icon = this.props.active
? 'my-icon-active'
: 'my-icon-inactive';
<Image source={require('./' + icon + '.png')} />;

// GOOD
const icon = this.props.active
? require('./my-icon-active.png')
: require('./my-icon-inactive.png');
<Image source={icon} />;

请注意,通过这种方式导入的图片源包含图片的尺寸(宽度、高度)信息。如果你需要动态缩放图片(例如,通过 flex),你可能需要在样式属性上手动设置 {width: undefined, height: undefined}

静态非图片资源

上述 require 语法也可用于在项目中静态包含音频、视频或文档文件。支持大多数常见文件类型,包括 .mp3.wav.mp4.mov.html.pdf。有关完整列表,请参阅 打包器默认设置

你可以通过在 Metro 配置中添加 assetExts 解析器选项来添加对其他类型的支持。

需要注意的是,视频必须使用绝对定位而不是 flexGrow,因为目前非图片资产不传递尺寸信息。对于直接链接到 Xcode 或 Android 的 Assets 文件夹中的视频,不存在此限制。

混合应用资源中的图片

如果你正在构建混合应用(部分 UI 使用 React Native,部分 UI 使用平台原生代码),你仍然可以使用已打包到应用中的图片。

对于通过 Xcode 资产目录或 Android drawable 文件夹中包含的图片,请使用不带扩展名的图片名称:

tsx
<Image
source={{uri: 'app_icon'}}
style={{width: 40, height: 40}}
/>

对于 Android assets 文件夹中的图片,请使用 asset:/ 方案:

tsx
<Image
source={{uri: 'asset:/app_icon.png'}}
style={{width: 40, height: 40}}
/>

这些方法不提供安全检查。你需要自行确保这些图片在应用中可用。此外,你必须手动指定图片尺寸。

网络图片

你将在应用中显示的许多图片在编译时可能不可用,或者你希望动态加载一些图片以减小二进制文件的大小。与静态资源不同,你将需要手动指定图片的尺寸。强烈建议你同时使用 HTTPS,以满足 iOS 上的 App Transport Security 要求。

tsx
// GOOD
<Image source={{uri: 'https://reactjs.ac.cn/logo-og.png'}}
style={{width: 400, height: 400}} />

// BAD
<Image source={{uri: 'https://reactjs.ac.cn/logo-og.png'}} />

图片的网络请求

如果你想在图片请求中设置 HTTP-Verb、Headers 或 Body 等,你可以通过在源对象上定义这些属性来完成:

tsx
<Image
source={{
uri: 'https://reactjs.ac.cn/logo-og.png',
method: 'POST',
headers: {
Pragma: 'no-cache',
},
body: 'Your Body goes here',
}}
style={{width: 400, height: 400}}
/>

URI 数据图片

有时,你可能会从 REST API 调用中获取编码的图片数据。你可以使用 'data:' URI 方案来使用这些图片。与网络资源一样,你将需要手动指定图片的尺寸

信息

这仅建议用于非常小且动态的图片,例如数据库列表中的图标。

tsx
// include at least width and height!
<Image
style={{
width: 51,
height: 51,
resizeMode: 'contain',
}}
source={{
uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADMAAAAzCAYAAAA6oTAqAAAAEXRFWHRTb2Z0d2FyZQBwbmdjcnVzaEB1SfMAAABQSURBVGje7dSxCQBACARB+2/ab8BEeQNhFi6WSYzYLYudDQYGBgYGBgYGBgYGBgYGBgZmcvDqYGBgmhivGQYGBgYGBgYGBgYGBgYGBgbmQw+P/eMrC5UTVAAAAABJRU5ErkJggg==',
}}
/>

缓存控制

在某些情况下,你可能只希望在图片已存在于本地缓存中时显示它,即在更高分辨率可用之前显示低分辨率占位符。在其他情况下,你可能不关心图片是否过时,并愿意显示过时的图片以节省带宽。cache 源属性使你可以控制网络层与缓存的交互方式。

  • default:使用原生平台的默认策略。
  • reload:将从原始源加载 URL 的数据。不应使用任何现有缓存数据来满足 URL 加载请求。
  • force-cache:无论其使用期限或到期日期如何,都将使用现有缓存数据来满足请求。如果缓存中没有与请求对应的现有数据,则从原始源加载数据。
  • only-if-cached:无论其使用期限或到期日期如何,都将使用现有缓存数据来满足请求。如果缓存中没有与 URL 加载请求对应的现有数据,则不会尝试从原始源加载数据,并且该加载被视为失败。
tsx
<Image
source={{
uri: 'https://reactjs.ac.cn/logo-og.png',
cache: 'only-if-cached',
}}
style={{width: 400, height: 400}}
/>

本地文件系统图片

有关使用 Images.xcassets 外部本地资源的示例,请参阅 CameraRoll

Drawable 资源

Android 支持通过 xml 文件类型加载 drawable 资源。这意味着你可以使用 矢量 drawable 来渲染图标,或者使用 形状 drawable 来绘制形状!你可以像使用任何其他静态资源混合资源一样导入和使用这些资源类型。你必须手动指定图片尺寸。

对于与 JS 代码位于一起的静态 drawable,请使用 requireimport 语法(两者功能相同):

tsx
<Image
source={require('./img/my_icon.xml')}
style={{width: 40, height: 40}}
/>

对于 Android drawable 文件夹(即 res/drawable)中包含的 drawable,请使用不带扩展名的资源名称:

tsx
<Image
source={{uri: 'my_icon'}}
style={{width: 40, height: 40}}
/>

drawable 资源与其他图片类型的一个主要区别在于,资产必须在 Android 应用程序编译时引用,因为 Android 需要运行 Android 资产打包工具 (AAPT) 来打包资产。AAPT 创建的文件格式(二进制 XML)无法通过网络由 Metro 加载。如果你更改资产的目录或名称,每次都需要重新构建 Android 应用程序。

创建 XML drawable 资源

Android 在其 Drawable 资源指南中提供了有关每种支持的 drawable 资源类型的全面文档,以及原始 XML 文件的示例。你可以利用 Android Studio 中的工具,如 Vector Asset Studio,从可缩放矢量图形 (SVG) 和 Adobe Photoshop 文档 (PSD) 文件创建矢量 drawable。

信息

如果你想将创建的 XML 文件视为静态图片资源(即使用 importrequire 语句),应尽量避免在 XML 文件中引用其他资源。如果你希望利用对其他 drawable 或属性的引用,例如颜色状态列表尺寸资源,则应将 drawable 作为混合资源包含并按名称导入。

最佳相册图片

iOS 在你的相册中保存同一图片的不同尺寸,出于性能原因选择最接近的尺寸非常重要。你不会希望在显示 200x200 缩略图时使用 3264x2448 的全质量图片作为源。如果存在完全匹配的图片,React Native 将选择它,否则它将使用第一个至少大 50% 的图片,以避免从接近尺寸调整大小时的模糊。所有这些都是默认完成的,所以你无需担心自己编写繁琐(且容易出错)的代码来完成。

为什么不自动调整所有尺寸?

在浏览器中,如果你不给图片指定尺寸,浏览器会渲染一个 0x0 的元素,下载图片,然后根据正确的尺寸渲染图片。这种行为的主要问题是,随着图片加载,你的 UI 会跳动,这会带来非常糟糕的用户体验。这被称为累积布局偏移

在 React Native 中,这种行为是故意不实现的。开发者预先知道远程图片的尺寸(或宽高比)会增加工作量,但我们相信这会带来更好的用户体验。通过 require('./my-icon.png') 语法从应用包中加载的静态图片可以自动调整尺寸,因为它们的尺寸在挂载时立即可用。

例如,require('./my-icon.png') 的结果可能是:

tsx
{"__packager_asset":true,"uri":"my-icon.png","width":591,"height":573}

源对象

在 React Native 中,一个有趣的决定是 src 属性被命名为 source,并且它不接受字符串,而是接受一个带有 uri 属性的对象。

tsx
<Image source={{uri: 'something.jpg'}} />

从基础设施方面来看,原因在于它允许我们将元数据附加到此对象。例如,如果你使用 require('./my-icon.png'),那么我们会添加有关其实际位置和大小的信息(请勿依赖此事实,它将来可能会改变!)。这也是为了面向未来,例如我们可能希望在某个时候支持精灵图,届时可以输出 {uri: ..., crop: {left: 10, top: 50, width: 20, height: 40}} 而不是 {uri: ...},并在所有现有调用点上透明地支持精灵图。

在用户端,这允许你使用有用的属性来标注对象,例如图片的尺寸,以便计算其将显示的尺寸。你可以随意将其用作数据结构,以存储有关图片的更多信息。

通过嵌套实现背景图片

熟悉 Web 开发的开发者常会提出 background-image 的功能请求。为了处理这个用例,你可以使用 <ImageBackground> 组件,它与 <Image> 具有相同的 props,并且你可以将任何子元素添加到其上方进行分层显示。

在某些情况下,你可能不希望使用 <ImageBackground>,因为其实现较为基础。有关更多信息,请参阅 <ImageBackground>文档,并在需要时创建自己的自定义组件。

tsx
return (
<ImageBackground source={...} style={{width: '100%', height: '100%'}}>
<Text>Inside</Text>
</ImageBackground>
);

请注意,你必须指定一些 widthheight 样式属性。

iOS 边框半径样式

请注意,iOS 的图片组件可能会忽略以下特定于角落的边框半径样式属性:

  • borderTopLeftRadius
  • borderTopRightRadius
  • borderBottomLeftRadius
  • borderBottomRightRadius

离线程解码

图片解码可能需要超过一帧的时间。这是 Web 上帧丢失的主要原因之一,因为解码是在主线程中完成的。在 React Native 中,图片解码在不同的线程中完成。实际上,你已经需要处理图片尚未下载的情况,因此在解码期间额外显示几帧占位符不需要任何代码更改。

配置 iOS 图片缓存限制

在 iOS 上,我们提供了一个 API 来覆盖 React Native 的默认图片缓存限制。这应该从你的原生 AppDelegate 代码中调用(例如在 didFinishLaunchingWithOptions 中)。

objectivec
RCTSetImageCacheLimits(4*1024*1024, 200*1024*1024);

参数

名称类型必需描述
imageSizeLimitnumber图片缓存大小限制。
totalCostLimitnumber总缓存成本限制。

在上述代码示例中,图片大小限制设置为 4 MB,总成本限制设置为 200 MB。