图片
静态图片资源
React Native 提供了一种统一的方式来管理 Android 和 iOS 应用中的图片和其他媒体资源。要向你的应用添加静态图片,请将其放置在源代码树中的某个位置,并像这样引用它
<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
代码包含
<Image source={require('./img/check.png')} />
...打包器将打包并提供与设备屏幕密度相对应的图片。例如,[email protected]
将在 iPhone 7 上使用,而 [email protected]
将在 iPhone 7 Plus 或 Nexus 5 上使用。如果没有与屏幕密度匹配的图片,则会选择最接近的最佳选项。
在 Windows 上,如果你向项目中添加了新的图片,可能需要重新启动打包器。
以下是你可以获得的一些好处
- Android 和 iOS 上使用相同的系统。
- 图片与你的 JavaScript 代码位于同一个文件夹中。组件是自包含的。
- 没有全局命名空间,即你无需担心名称冲突。
- 只有实际使用的图片才会打包到你的应用中。
- 添加和更改图片不需要重新编译应用,你可以像往常一样刷新模拟器。
- 打包器知道图片的尺寸,无需在代码中重复。
- 图片可以通过 npm 包进行分发。
为了使此功能正常工作,require
中的图片名称必须是静态已知的。
// 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} />;
请注意,以这种方式需要的图片源包含 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 文件夹包含的图片,请使用不带扩展名的图片名称
<Image
source={{uri: 'app_icon'}}
style={{width: 40, height: 40}}
/>
对于 Android assets 文件夹中的图片,请使用 asset:/
方案
<Image
source={{uri: 'asset:/app_icon.png'}}
style={{width: 40, height: 40}}
/>
这些方法不提供任何安全检查。你需要确保这些图片在应用中可用。此外,你还必须手动指定图片尺寸。
网络图片
你将在应用中显示的许多图片在编译时都不可用,或者你希望动态加载一些图片以减小二进制文件的大小。与静态资源不同,你需要手动指定图片的尺寸。强烈建议你使用 https,以便满足 iOS 上的 应用传输安全 要求。
// 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 之类的内容以及图片请求,可以通过在源对象上定义这些属性来实现
<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 方案来使用这些图片。与网络资源一样,你需要手动指定图片的尺寸。
仅建议用于非常小且动态的图片,例如来自数据库的列表中的图标。
// 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==',
}}
/>
缓存控制(仅限 iOS)
在某些情况下,你可能只想在图片已存在于本地缓存中时才显示它,例如,在更高分辨率的图片可用之前显示低分辨率的占位符。在其他情况下,你并不关心图片是否已过期,并且愿意显示过期的图片以节省带宽。cache
源属性使你可以控制网络层如何与缓存交互。
default
:使用原生平台的默认策略。reload
:将从原始源加载 URL 的数据。不应使用任何现有的缓存数据来满足 URL 加载请求。force-cache
:将使用现有的缓存数据来满足请求,无论其年龄或过期日期如何。如果缓存中不存在与请求相对应的现有数据,则从原始源加载数据。only-if-cached
:将使用现有的缓存数据来满足请求,无论其年龄或过期日期如何。如果缓存中不存在与 URL 加载请求相对应的现有数据,则不会尝试从原始源加载数据,并且加载被视为失败。
<Image
source={{
uri: 'https://reactjs.ac.cn/logo-og.png',
cache: 'only-if-cached',
}}
style={{width: 400, height: 400}}
/>
本地文件系统图片
请参阅 CameraRoll 以获取使用位于 Images.xcassets
之外的本地资源的示例。
最佳相机胶卷图片
iOS 会在你的相机胶卷中保存同一图片的多个尺寸,出于性能原因,选择尽可能接近的尺寸非常重要。当你显示 200x200 的缩略图时,你不会希望使用 3264x2448 的全质量图片作为源。如果存在完全匹配的图片,React Native 将选择它,否则它将使用第一个至少大 50% 的图片,以避免在从接近的尺寸调整大小时出现模糊。所有这些都是默认完成的,因此你无需担心编写乏味(且容易出错)的代码来自己完成它。
为什么不自动调整所有图片的大小?
在浏览器中,如果你没有为图片指定大小,浏览器将呈现一个 0x0 元素,下载图片,然后根据正确的大小呈现图片。此行为带来的最大问题是你的 UI 会随着图片加载而四处跳动,这会导致非常糟糕的用户体验。这被称为 累积布局偏移。
在 React Native 中,此行为有意未实现。开发人员需要提前了解远程图片的尺寸(或纵横比),这会增加一些工作量,但我们认为这可以带来更好的用户体验。通过 require('./my-icon.png')
语法从应用包加载的静态图片可以自动调整大小,因为它们的尺寸在挂载时即可立即获得。
例如,require('./my-icon.png')
的结果可能是
{"__packager_asset":true,"uri":"my-icon.png","width":591,"height":573}
源作为对象
在 React Native 中,一个有趣的决定是 src
属性被命名为 source
,并且不接受字符串,而是一个包含 uri
属性的对象。
<Image source={{uri: 'something.jpg'}} />
在基础设施方面,这样做是为了让我们能够附加元数据到这个对象。例如,如果你使用的是require('./my-icon.png')
,那么我们会添加关于其实际位置和大小的信息(不要依赖这个事实,它将来可能会改变!)。这也是为了面向未来,例如我们可能希望在某些时候支持精灵图,而不是输出{uri: ...}
,我们可以输出{uri: ..., crop: {left: 10, top: 50, width: 20, height: 40}}
,并透明地支持所有现有调用站点上的精灵图。
在用户端,这允许你使用有用的属性(例如图像的尺寸)来注释对象,以便计算它将要显示的大小。随意将其用作你的数据结构来存储有关图像的更多信息。
通过嵌套实现背景图片
熟悉 Web 的开发者经常会提出一个功能请求:background-image
。为了处理这种情况,你可以使用<ImageBackground>
组件,它与<Image>
具有相同的 props,并将你想要在其上叠加的任何子元素添加到其中。
在某些情况下,你可能不希望使用<ImageBackground>
,因为它的实现比较基础。请参阅<ImageBackground>
的文档以了解更多信息,并在需要时创建你自己的自定义组件。
return (
<ImageBackground source={...} style={{width: '100%', height: '100%'}}>
<Text>Inside</Text>
</ImageBackground>
);
请注意,你必须指定一些宽度和高度样式属性。
iOS 圆角样式
请注意,以下特定于角的圆角样式属性可能会被 iOS 的图像组件忽略
borderTopLeftRadius
borderTopRightRadius
borderBottomLeftRadius
borderBottomRightRadius
异步解码
图像解码可能需要超过一帧的时间。这是 Web 上导致帧下降的主要原因之一,因为解码是在主线程中完成的。在 React Native 中,图像解码是在不同的线程中完成的。实际上,你已经需要处理图像尚未下载的情况,因此在解码期间将占位符显示几帧更多的时间不需要任何代码更改。
配置 iOS 图像缓存限制
在 iOS 上,我们提供了一个 API 来覆盖 React Native 的默认图像缓存限制。这应该在你的原生 AppDelegate 代码中调用(例如,在didFinishLaunchingWithOptions
中)。
RCTSetImageCacheLimits(4*1024*1024, 200*1024*1024);
参数
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
imageSizeLimit | 数字 | 是 | 图像缓存大小限制。 |
totalCostLimit | 数字 | 是 | 总缓存成本限制。 |
在上面的代码示例中,图像大小限制设置为 4 MB,总成本限制设置为 200 MB。