Image组件
Image组件
用于显示多种不同类型图片的React Native
组件,包括网络图片、静态资源、临时的本地图片、以及本地磁盘上的图片(如相册)等。
1、加载网络图片
render() {
return (
<View style={styles.container}>
<Image style={styles.imageStyle}
source={{uri: imageAddress}}/>
</View>
);
}
imageAddress
图片地址,你需要手动指定图片的尺寸
,如果没有声明,则图片将不会被呈现在界面上。。同时我们强烈建议你使用 https 以满足 iOS App Transport Security 的要求。指定source
属性来显示图片,imageStyle
图片显示样式
// 正确
<Image source={{uri: 'https://facebook.github.io/react/logo-og.png'}}
style={{width: 400, height: 400}} />
// 错误
<Image source={{uri: 'https://facebook.github.io/react/logo-og.png'}} />
简单使用
import React, {Component} from 'react';
import {
Image, StyleSheet, View
} from 'react-native';
export default class ImageComponent extends Component {
render() {
return (
<View style={styles.container}>
<Image style={styles.imageStyle}
source={{uri:'https://facebook.github.io/react/logo-og.png'}}/>
</View>
);
}
}
// 指定显示样式
var styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
imageStyle: {
top: 50,
left: 50,
width: 200,
height: 200,
}
});
实现效果
加载data类型数据图片
有时候你可能拿到的是图片的base64
数据,此时可以使用'data:'格式来显示图片。请注意,你需要手动指定图片的尺寸。
建议仅对非常小的图片使用 base64 数据,比如一些小图标。
// 请记得指定宽高!
<Image
style={{
width: 51,
height: 51,
resizeMode: 'contain',
}}
source={{
uri:
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADMAAAAzCAYAAAA6oTAqAAAAEXRFWHRTb2Z0d2FyZQBwbmdjcnVzaEB1SfMAAABQSURBVGje7dSxCQBACARB+2/ab8BEeQNhFi6WSYzYLYudDQYGBgYGBgYGBgYGBgYGBgZmcvDqYGBgmhivGQYGBgYGBgYGBgYGBgYGBgbmQw+P/eMrC5UTVAAAAABJRU5ErkJggg==',
}}
/>
2、静态图片资源
React Native
提供了一个统一的方式来管理iOS 和 Android
应用中的图片。要往 App 中添加一个静态图片,只需把图片文件放在代码文件夹中某处,然后像下面这样去引用它,require
等同于使用var声明了一个变量:
<Image source={require('./my-icon.png')} />
图片文件的查找会和 JS 模块的查找方式一样。在上面的这个例子里,是哪个组件引用了这个图片,Packager
就会去这个组件所在的文件夹下查找my-icon.png
。并且,如果你有my-icon.ios.png
和my-icon.android.png
,Packager
就会根据平台而选择不同的文件。
你还可以使用@2x,@3x这样的文件名后缀,来为不同的屏幕精度提供图片。比如下面这样的代码结构:
.
├── button.js
└── img
├── check.png
├── check@2x.png
└── check@3x.png
并且button.js
里有这样的代码:
<Image source={require('./img/check.png')} />
Packager 会打包所有的图片并且依据屏幕精度提供对应的资源。譬如说,iPhone 7 会使用check@2x.png,而 iPhone 7 plus 或是 Nexus 5 上则会使用check@3x.png。如果没有图片恰好满足屏幕分辨率,则会自动选中最接近的一个图片。
注意:如果你添加图片的时候 packager 正在运行,可能需要重启 packager 以便能正确引入新添加的图片。
这样会带来如下的一些好处:
- iOS 和 Android 一致的文件系统。
- 图片和 JS 代码处在相同的文件夹,这样组件就可以包含自己所用的图片而不用单独去设置。
- 不需要全局命名。你不用再担心图片名字的冲突问题了。
- 只有实际被用到(即被 require)的图片才会被打包到你的 app。
- 现在在开发期间,增加和修改图片不需要重新编译了,只要和修改 js 代码一样刷新你的模拟器就可以了。
- 与访问网络图片相比,Packager 可以得知图片大小了,不需要在代码里再声明一遍尺寸。
- 现在通过 npm 来分发组件或库可以包含图片了。
注意:为了使新的图片资源机制正常工作,require 中的图片名字必须是一个静态字符串(不能使用变量!因为 require 是在编译时期执行,而非运行时期执行!)。
// 正确
<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} />;
请注意:通过这种方式引用的图片资源包含图片的尺寸(宽度,高度)信息,如果你需要动态缩放图片(例如,通过 flex),你可能必须手动在 style 属性设置
{ width: null, height: null }
。
3、网络图片的请求参数
可以在Image
组件的source
属性中指定一些请求参数,如下面的示例:
<Image
source={{
uri: 'https://facebook.github.io/react/logo-og.png',
method: 'POST',
headers: {
Pragma: 'no-cache',
},
body: 'Your Body goes here',
}}
style={{width: 400, height: 400}}
/>
4、使用getSize获取图片的宽和高
getSize()函数
Image
组件提供了一个静态函数getSize
,用来取得指定URL
地址图片的宽和高(单位为像素)。
注意:在调用 getSize 函数取图片的宽、高时,React Native 框架事实上会下载这张图片,并且将该图片保存到缓存中。所以 getSize 函数也可以作为预加载图片资源的一个方法。
原生方式
let imageSource = "https://facebook.github.io/react/logo-og.png";
Image.getSize(imageSource, (width, height) => {
console.log(`The image dimensions are ${width}x${height}`);
}, (error) => {
console.error(`Couldn't get the image size: ${error.message}`);
});
promise方式
Image.getSize(imageSource).then((width, height) => {
//取得图片的宽高,并进行相应的处理
//......
}).catch((error) => {
//下载图片失败
console.log(error);
});
5、使用prefetch预获取图片
可以使用Image
组件的静态函数 prefetch
来预下载某张网络图片。
let imageSource = "https://facebook.github.io/react/logo-og.png";
Image.prefetch(imageSource, (result) => {
console.log(`The image prefetch are ${result}`);
}, (error) => {
console.error(`Couldn't get the image size: ${error.message}`);
});
6、目前支持的属性
-
resizeMode
:表示内部图片的显示模式。是一个枚举类型,具体用法在下面会有介绍。 -
source
:图片的引用地址,其值为 {uri:string}。如果是一个本地的静态资源,那么需要使用 require('string') 包裹。 -
defaultSource
:表示图片未加载完成时,使用的默认图片地址。(仅iOS支持)
-onLoadStart
:加载开始时触发该事件(仅iOS支持) -
onProgress
:加载过程的进度事件。(仅iOS支持) -
onLoad
:加载成功时触发该事件。(仅iOS支持) -
onLoadEnd
:不管是加载成功还是失败,都会触发该事件。(仅iOS支持)
支持的图片格式
- React Native 默认支持 JPG、PNG 格式。
- 在 iOS 平台下,还支持 GIF、WebP 格式。
- 在 Android 平台下,默认不支持 GIF、WebP 格式。可以通过修改 Android 工程设置让其支持这两种格式:
打开项目目录下的 android/app/build.gradle,视情况添加相关代码:
dependencies {
compile 'com.facebook.fresco:animated-gif:0.11.0' //需要GIF动画支持添加本行语句
compile 'com.facebook.fresco:webpsupport:0.11.0' //需要WebP格式支持添加本行语句
compile 'com.facebook.fresco:animated-webp:0.11.0' //需要WebP动画支持添加本行语句
}
设置图像显示模式
- resizeMode
当 Image 组件的实际宽、高与图片的实际宽、高不符时,要如何显示图片由样式定义中resizeMode
取值来决定。resizeMode
的五个取值分别是:contain、cover、stretch、center 和 repeat
。如果没有定义resizeMode
,默认值为:cover
。其中 repeat
只对 iOS 平台有效。
无论resizeMode
取值如何,图片都会在 Image 组件的显示区域居中显示。即显示的图片中点与显示区域的中点是一个点。
resizeMode
比较特殊,可以按需要,自由放置在如下两个地方:既可以作为 Image
组件样式中的一个键值对发挥作用。也可以作为Image
组建的属性来发挥作用。
- 各种模式
cover 模式(默认值)
该模式要求图片能够填充整个 Image
组件定义的显示区域,可以对图片进行放大或者缩小,可以丢弃放大或缩小后的图片中的部分区域,只求在显示比例不失真的情况下填充整个显示区域。
如果图片的宽、高有一个值小于Image
的实际宽、高,React Native
会对图片进行放大,直到图片的宽与高均不小于Image
的实际宽、高。然后将放大的图片居中显示,超出显示区域的部分被直接丢弃。
如果图片的宽、高均大于 Image
的实际宽、高, React Native
会对图片进行等比缩小,直到缩小后图片的宽、高有一个值等于Image
的实际宽、高。然后将缩小后的图片居中显示,超出区域的部分被直接丢弃。
contain 模式
该模式要求显示整张图片,可以对它进行等比放大或者缩小,但不能丢弃改变后图片的某部分。这个模式下图片得到完整的呈现,比例不会变。但图片可能无法填充 Image
的所有区域,会在侧边或者上下留下空白,由Image
组件的底色填充。
如果图片的实际宽、高都小于Image
的实际宽、高, React Native
会对图片进行等比放大,直到宽、高中有一个值等于Image
的实际宽、高。然后居中显示图片。
如果图片的实际宽、高有一个值或者都大于 Image
的实际宽、高, React Native
会对图片进行等比缩小,直到缩小后图片的宽、高有一个不小于 Image 的实际宽、高,然后在Image
中展现图片。
stretch 模式
该模式要求图片填充整个Image
定义的显示区域,因此会对图片进行任意的缩放,不考虑保持图片原来的宽、高比。这种模式显示出来的图片有可能会出现明显的失真。
center 模式
该模式要求图片图片位于显示区域的中心。这种模式下图片可能也无法填充 Image
的所有区域,会在侧边或者上下留下空白,由 Image
组件的底色填充。
如果图片的实际宽、高都小于 Image
的实际宽、高, React Native
不会对图片进行任何缩放,只是把它居中呈现在父 View
中。
如果图片的实际宽、高有一个值或者都大于Image
的实际宽、高, React Native
会对图片进行等比缩小,直到缩小后图片的宽、高有一个不小于 Image
的实际宽、高,然后在Image
中展现图片。
repeat 模式(iOS 独有)
该模式的图片处理思路是用一张或者多张图片来填充整个 Image 定义的显示区域。
7、使用混合 App 的图片资源
如果你在编写一个混合App
(一部分 UI 使用 React Native
,而另一部分使用平台原生代码),也可以使用已经打包到 App
中的图片资源(以拖拽的方式放置在Xcode
的 asset
类目中,或是放置在 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}} />
注意:这些做法并没有任何安全检查。你需要自己确保图片在应用中确实存在,而且还需要指定尺寸。
8、缓存控制(仅 iOS)
React Native
支持对网络图片的缓存,访问过一次的图片,在一定时间内会缓存到手机中,当需要再次显示的时候,React Native
将会从手机存储中加载这个缓存,而不是从网络获取
在Andriod
平台,图片是会缓存到本地的,对于iOS
需要设置cache
属性实现缓存效果
-
default
: 使用原生平台默认策略。 -
reload
: URL 的数据将从原始地址加载。不使用现有的缓存数据。 -
force-cache
: 现有的缓存数据将用于满足请求,忽略其期限或到期日。如果缓存中没有对应请求的数据,则从原始地址加载。 -
only-if-cached
: 现有的缓存数据将用于满足请求,忽略其期限或到期日。如果缓存中没有对应请求的数据,则不尝试从原始地址加载,并且认为请求是失败的。
<Image
source={{
uri: 'https://facebook.github.io/react/logo-og.png',
cache: 'only-if-cached',
}}
style={{width: 400, height: 400}}
/>
9、背景图片与嵌套写法
开发者们常面对的一种需求就是类似web
中的背景图(background-image
)文档。要实现这一用例,只需使用<ImageBackground>
组件(其 props 与<Image>
完全相同),然后把需要背景图的子组件嵌入其中即可。
// 注意你必须指定宽高样式。
return (
<ImageBackground source={...} style={{width: '100%', height: '100%'}}>
<Text>Inside</Text>
</ImageBackground>
);
简单例子
1、加载图片
import React, { Component } from 'react';
import { View, Image, Text, StyleSheet, Platform, ActivityIndicator } from 'react-native';
export default class ImageExample extends Component {
constructor() {
super();
// 宽、高、是否正在加载、URL等属性
this.state = { width: 0, height: 0, loading: true }
this.uri = 'https://tutorialscapital.com/wp-content/uploads/2017/09/background.jpg';
}
// 组件出现之后获取图片大小
componentDidMount() {
Image.getSize( this.uri, ( width, height ) => {
this.setState({ width: width, height: height, loading: false });
}, ( error ) => {
this.setState({ loading: false });
console.log( error );
});
}
render(){
return(
<View style = { styles.container }>
<View style = { styles.imageContainer }>
{
( this.state.loading )
?
<ActivityIndicator size = "large" />
:
( <Image source = {{ uri: this.uri }} style = { styles.image } /> )
}
<View style = { styles.showDimensionsView }>
<Text style = { styles.text }>{ this.state.width }(w) X { this.state.height }(h)</Text>
</View>
</View>
</View>
);
}
}
// 定义显示样式
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
paddingTop: ( Platform.OS === 'ios' ? 20 : 0 )
},
imageContainer: {
position: 'relative',
width: 200,
height: 250,
justifyContent: 'center',
alignItems: 'center'
},
image: {
resizeMode: 'cover',
width: '100%',
height: '100%'
},
showDimensionsView: {
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0,0,0,0.6)',
alignItems: 'center',
paddingTop: 15,
paddingBottom: 15
},
text: {
fontSize: 20,
color: 'black',
color: 'rgba(255,255,255,0.8)'
}
});
刚开始会显示图片加载指示器,当图片获取大小成功之后会设置图片属性,重新渲染显示图片
实现效果
2、简单的图片浏览器
这里实现一个简单的图片浏览器,通过点击下方的“上一张”和“下一张”按钮可以进行图片的切换
import React, {Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Image,
TouchableOpacity
} from 'react-native';
// 网络图片数组
var imgs = [
'https://img3.doubanio.com/view/movie_poster_cover/mpst/public/p2263582212.jpg',
'https://img3.doubanio.com/view/movie_poster_cover/mpst/public/p2265761240.jpg',
'https://img3.doubanio.com/view/movie_poster_cover/mpst/public/p2266110047.jpg'
];
// 定义图片浏览组件
class MyImage extends Component {
//构造函数
constructor(props) {
super(props);
this.state = {
imgs: props.imgs,
count: 0
};
}
//下一张按钮点击事件
goNext() {
var count = this.state.count;
count++;
if (count < imgs.length) {
this.setState({count: count});
}
}
//上一张按钮点击事件
goPreview() {
var count = this.state.count;
count --;
if(count >= 0){
this.setState({count: count});
}
}
render() {
return (
<View style={[styles.flex]}>
<View style={styles.image}>
<Image style={styles.img}
source={{uri: this.state.imgs[this.state.count]}}
resizeMode="contain" />
</View>
<View style={styles.btns}>
<TouchableOpacity onPress={this.goPreview.bind(this)}>
<View style={styles.btn}>
<Text>上一张</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={this.goNext.bind(this)}>
<View style={styles.btn}>
<Text>下一张</Text>
</View>
</TouchableOpacity>
</View>
</View>
);
}
}
//默认应用的容器组件
export default class MyNextImage extends Component {
// 容器组件,显示MyImage组件
render() {
return (
<View style={[styles.flex, {marginTop:40}]}>
<MyImage imgs={imgs}></MyImage>
</View>
);
}
}
// 样式定义
const styles = StyleSheet.create({
flex:{
flex: 1,
alignItems:'center'
},
image:{
borderWidth:1,
width:300,
height:200,
borderRadius:5,
borderColor:'#ccc'
},
img:{
height:198,
width:300,
},
btns:{
flexDirection: 'row',
justifyContent: 'center',
marginTop:20
},
btn:{
width:60,
height:30,
borderColor: '#0089FF',
borderWidth: 1,
justifyContent: 'center',
alignItems:'center',
borderRadius:3,
marginRight:20,
},
});
实现效果