一. 简介
一个用于显示多种不同类型图片的React组件,包括网络图片、静态资源、临时的本地图片、以及本地磁盘上的图片(如相册)等。
从0.14版本开始,React Native提供了一个统一的方式来管理iOS和Android应用中的图片。要往App中添加一个静态图片,只需把图片文件放在代码文件夹比如img中某处,然后像下面这样去引用它:<Image source={require(‘./img/check.png‘)} />
如果你有my-icon.ios.png和my-icon.android.png,Packager就会根据平台而选择不同的文件。
你还可以使用@2x,@3x这样的文件名后缀,来为不同的屏幕精度提供图片。比如下面这样的代码结构:
------ button.js
------ img
------ |-------- [email protected]
------ |-------- [email protected]
Packager会打包所有的图片并且依据屏幕精度提供对应的资源。譬如说,iPhone 5s会使用[email protected],而Nexus 5上则会使用[email protected]。如果没有图片恰好满足屏幕分辨率,则会自动选中最接近的一个图片。
【注意】如果你添加图片的时候packager正在运行,可能需要重启packager以便能正确引入新添加的图片。为了使新的图片资源机制正常工作,require中的图片名字必须是一个静态字符串,不能在require中进行拼接。
//正确<Image source={require(‘./my-icon.png‘)} />
错误var icon = this.props.active ? ‘my-icon-active‘ : ‘my-icon-inactive‘;
<Image source={require(‘./‘ + icon + ‘.png‘)} />
使用混合App的图片资源
如果你在编写一个混合App(一部分UI使用React Native,而另一部分使用平台原生代码),也可以使用已经打包到App中的图片资源(通过Xcode的asset类目或者Android的drawable文件夹打包):<Image source={{uri: ‘app_icon‘}} style={{width: 40, height: 40}} />
注意:这一做法并没有任何安全检查。你需要自己确保图片在应用中确实存在,而且还需要指定尺寸。
加载网络图片
与静态资源不同的是,你需要手动指定图片的尺寸。
//正确<Image source={{uri: ‘https://facebook.github.io/react/img/logo_og.png‘}}
style={{width: 400, height: 400}} />
//错误<Image source={{uri: ‘https://facebook.github.io/react/img/logo_og.png‘}} />
为什么不在所有情况下都指定尺寸呢
在浏览器中,如果你不给图片指定尺寸,那么浏览器会首先渲染一个0x0大小的元素占位,然后下载图片,在下载完成后再基于正确的尺寸来渲染图片。这样做的最大问题是UI会在图片加载的过程中上下跳动,使得用户体验非常糟糕。
在React
Native中有意避免了这一行为。如此一来开发者就需要做更多工作来提前知晓远程图片的尺寸(或宽高比),但我们相信这样可以带来更好的用户体验。然而,从已经打包好的应用资源文件中读取图片(使用require(‘image!x‘)语法)则无需指定尺寸,因为它们的尺寸在加载时就可以立刻知道。
比如这样一个引用require(‘image!logo‘)的实际输出结果可能是:{"__packager_asset":true,"isStatic":true,"path":"/Users/react/HelloWorld/iOS/Images.xcassets/react.imageset/logo.png","uri":"logo","width":591,"height":573}
通过嵌套实现背景图片
类似web中的背景图(background-image),只需简单地创建一个<Image>组件,然后把需要背景图的子组件嵌入其中即可return (
<Image source={...}>
<Text>Inside</Text>
</Image>
);
在Android 上支持GIF和WebP格式的图片
dependencies {
// 如果你需要支持Android4.0(API level 14)之前的版本
compile ‘com.facebook.fresco:animated-base-support:0.11.0‘
// 如果你需要支持GIF动图
compile ‘com.facebook.fresco:animated-gif:0.11.0‘
// 如果你需要支持WebP格式,包括WebP动图
compile ‘com.facebook.fresco:animated-webp:0.11.0‘
compile ‘com.facebook.fresco:webpsupport:0.11.0‘
// 如果只需要支持WebP格式而不需要动图
compile ‘com.facebook.fresco:webpsupport:0.11.0‘
}
如果你在使用GIF的同时还使用了ProGuard,那么需要在proguard-rules.pro中添加如下规则 :-keep class com.facebook.imagepipeline.animated.factory.AnimatedFactoryImpl { public AnimatedFactoryImpl(com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory, com.facebook.imagepipeline.core.ExecutorSupplier);
}
二. 属性
1.onLayout (function) 当Image布局发生改变的,会进行调用该方法,调用的代码为:
{nativeEvent: {layout: {x, y, width, height}}}.
2.onLoad (function):当图片加载成功之后,回调该方法
3.onLoadEnd (function):当图片加载失败回调该方法,不会管图片加载成功还是失败
4.onLoadStart (fcuntion):当图片开始加载的时候调用该方法
5.resizeMode 缩放比例,可选参数(‘cover‘, ‘contain‘, ‘stretch‘) 当图片的尺寸超过布局的尺寸的时候,会根据设置Mode进行缩放或者裁剪图片
cover: 在保持图片宽高比的前提下缩放图片,直到宽度和高度都大于等于容器视图的尺寸(如果容器有padding内衬的话,则相应减去)。译注:这样图片完全覆盖甚至超出容器,容器中不留任何空白。
contain: 在保持图片宽高比的前提下缩放图片,直到宽度和高度都小于等于容器视图的尺寸(如果容器有padding内衬的话,则相应减去)。译注:这样图片完全被包裹在容器中,容器中可能留有空白
stretch: 拉伸图片且不维持宽高比,直到宽高都刚好填满容器。
repeat: 重复平铺图片直到填满容器。图片会维持原始尺寸。仅iOS可用。
center: 居中不拉伸。
6.source {uri:string} 进行标记图片的引用,该参数可以为一个网络url地址或者一个本地(使用require(相对路径)来引用)的路径
三. 样式风格
1.FlexBox 支持弹性盒子风格
2.Transforms 支持属性动画 3.resizeMode 设置缩放模式
4.backgroundColor 背景颜色
5.borderColor 边框颜色 6.borderWidth 边框宽度
7.borderRadius 边框圆角
8.overflow 设置图片尺寸超过容器可以设置显示或者隐藏(‘visible‘,‘hidden‘)
9.tintColor 颜色设置 10.opacity 设置不透明度0.0(透明)-1.0(完全不透明)
四. 示例
加载网路图片的例子class MyImageDemo extends Component {
render() {
return (
<View style={[styles.flex,{marginTop:45}]}>
<MyImage imgs={imgs}> </MyImage>
</View>
);
}
}class MyImage extends Component {
constructor(props) {
super(props);
this.state = {
count: 0,//图片索引
imgs: this.props.imgs,
};
}render() {
return (
<View style={[styles.flex,{alignItems:‘center‘}]}>
<View style={styles.image}>
<Image style={styles.img}
resizeMode=‘contain‘
source={{uri:this.state.imgs[this.state.count]}}/>
</View>
<View style={styles.btns}>
<TouchableOpacity onPress={this.onPrevious.bind(this)}><View
style={styles.btn}><Text>上一张</Text></View></TouchableOpacity><TouchableOpacity onPress={this.onNext.bind(this)}><View style={styles.btn}><Text>下一张</Text></View></TouchableOpacity>
</View>
</View>
);
}onPrevious() {
var count = this.state.count;
count--;
if (count >= 0) {
this.setState({
count: count,
});
}
}
onNext() {
var count = this.state.count;
count++;
if (count < this.state.imgs.length) {
this.setState({
count: count,
});
}
}
}const styles = StyleSheet.create({
flex: {
flex: 1,
},
image: {
width: 300,
height: 200,
borderWidth: 1,
justifyContent: ‘center‘,
alignItems: ‘center‘,
borderColor: ‘#ccc‘,
borderRadius: 5,
},
img: {
width: 200,
height: 150,
},
btn: {
width: 60,
height: 35,
borderWidth: 1,
borderColor: ‘#ccc‘,
borderRadius: 3,
justifyContent: ‘center‘,
alignItems: ‘center‘,
marginRight: 30,
},
btns: {
flexDirection: ‘row‘,
marginTop: 20,
justifyContent: ‘center‘
}
}
);
效果
Image_first.jpeg
点击下一张
Image_second.jpeg
点击下一张
Image_third.jpeg
记录我自己的RN学习之路,纯属自己增值,有什么不对的地方,一起讨论进步