跳到主要内容
版本:0.80

图片

静态图片资源

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
// 好
<Image source={require('./my-icon.png')} />;

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

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

注意,以这种方式要求的图片源包含 Image 的尺寸(宽,高)信息。如果你需要动态缩放图片(即通过 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:/ scheme:

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

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

网络图片

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

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

// 坏
<Image source={{uri: 'https://reactjs.org/logo-og.png'}} />

图片的网络请求

如果你想随图片请求设置诸如 HTTP-Verb、Headers 或 Body 之类的内容,你可以通过在源对象上定义这些属性来实现:

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

URI 数据图片

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

信息

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

tsx
// 至少包含宽度和高度!
<Image
style={{
width: 51,
height: 51,
resizeMode: 'contain',
}}
source={{
uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADMAAAAzCAYAAAA6oTAqAAAAEXRFWHRTb2Z0d2FyZQBwbmdjcnVzaEB1SfMAAABQSURBVGje7dSxCQBACARB+2/ab8BEeQNhFi6WSYzYLYudDQYGBgYGBgYGBgYGBgYGBgZmcvDqYGBgmhivGQYGBgYGBgYGBgYGBgYGBgbmQw+P/eMrC5UTVAAAAABJRU5ErkJggg==',
}}
/>

缓存控制

在某些情况下,你可能只想显示已经在本地缓存中的图片,例如低分辨率占位符,直到高分辨率可用。在其他情况下,你不关心图片是否过时,并且愿意显示过时的图片以节省带宽。cache 源属性让你控制网络层如何与缓存交互。

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

本地文件系统图片

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

Drawable 资源

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

对于与 JS 代码位于一起的静态 drawables,使用 requireimport 语法(两者工作方式相同):

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

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

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

drawable 资源与其他图片类型之间的一个关键区别是,资产必须在 Android 应用的编译时被引用,因为 Android 需要运行 Android Asset Packaging Tool (AAPT) 来打包资产。AAPT 创建的文件格式二进制 XML 不能通过 Metro 通过网络加载。如果你更改资产的目录或名称,每次都需要重新构建 Android 应用。

创建 XML drawable 资源

Android 在其 Drawable 资源 指南中提供了每种支持的 drawable 资源类型的综合文档,以及原始 XML 文件的示例。你可以利用 Android Studio 中的工具,如 Vector Asset Studio,从 Scalable Vector Graphic (SVG) 和 Adobe Photoshop Document (PSD) 文件创建 vector drawables。

信息

如果你想将 XML 文件视为静态图片资源(即使用 importrequire 语句),你应该尽量避免在创建的 XML 文件中引用其他资源。如果你希望利用对其他 drawables 或属性的引用,如 color state listsdimension resources,你应该将你的 drawable 作为 混合资源 包含并通过名称导入它。

最佳 Camera Roll 图片

iOS 在你的 Camera Roll 中为同一图片保存多个尺寸,出于性能原因,选择尽可能接近的尺寸非常重要。当显示 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: ...},我们可以输出 {uri: ..., crop: {left: 10, top: 50, width: 20, height: 40}} 并在所有现有的调用站点透明地支持雪碧图。

在用户方面,这让你可以用有用的属性(例如图像的尺寸)来标注对象,以便计算它将显示的大小。随意将其用作数据结构来存储有关图像的更多信息。

通过嵌套实现背景图像

熟悉网页开发的开发者一个常见的功能请求是 background-image

要处理此用例,你可以使用 <ImageBackground> 组件,它具有与 <Image> 相同的 props,并可以向其中添加任何你想要覆盖在其上方的子元素。

在某些情况下你可能不想使用 <ImageBackground>,因为实现比较基础。请参阅 <ImageBackground>文档 以了解更多见解,并在需要时创建你自己的自定义组件。

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

请注意,你必须指定一些宽度和高度样式属性。

iOS 边框半径样式

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

  • borderTopLeftRadius
  • borderTopRightRadius
  • borderBottomLeftRadius
  • borderBottomRightRadius

非主线程解码

图像解码可能需要超过一帧的时间。这是网络上掉帧的主要来源之一,因为解码是在主线程中完成的。在 React Native 中,图像解码是在不同的线程中完成的。在实践中,你已经需要处理图像尚未下载的情况,因此在解码时多显示几帧占位符不需要任何代码更改。

配置 iOS 图像缓存限制

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

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

参数:

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

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