返回 导航

React / React Native

hangge.com

React Native - Image组件的使用详解(加载资源、网络、本地图片)

作者:hangge | 2017-02-21 08:10

一、Image组件介绍

HTMLimg 元素一样,React Native 提供的 Image 组件可以用来显示各种途径的图片,比如网络图片、本地磁盘图片、照相机图片等。

1,宽、高尺寸设置

(1)Image 组件必须在样式中声明图片的宽和高。如果没有声明,则图片将不会被呈现在界面上。
(2)有时我们需要将某张图片点对点地显示在手机上,如果我们知道图片实际分辨率(比如:actrualWidth * actrualHeight),那么可以使用如下方式定义图片显示样式:
import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Image,
  PixelRatio
} from 'react-native';

//.........
preciseImageStyle: {
  width: actrualWidth / PixelRatio.get(),
  height: actrualHeight / PixelRatio.get(),
}
//.........


2,目前支持的属性

  • resizeMode:表示内部图片的显示模式。是一个枚举类型,具体用法在下面会有介绍。
  • source:图片的引用地址,其值为 {uri:string}。如果是一个本地的静态资源,那么需要使用 require('string') 包裹。
  • defaultSource:表示图片未加载完成时,使用的默认图片地址。(仅iOS支持)
  • onLoadStart:加载开始时触发该事件(仅iOS支持)
  • onProgress:加载过程的进度事件。(仅iOS支持)
  • onLoad:加载成功时触发该事件。(仅iOS支持)
  • onLoadEnd:不管是加载成功还是失败,都会触发该事件。(仅iOS支持)

3,支持的图片格式

(1)React Native 默认支持 JPGPNG 格式。
(2)在 iOS 平台下,还支持 GIFWebP 格式。
(3)在 Android 平台下,默认不支持 GIFWebP 格式。可以通过修改 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动画支持添加本行语句
}

4,组件方法

(1)getSize()
Image 组件提供了一个静态函数 getSize,用来取得指定 URL 地址图片的宽和高(单位为像素)。
注意:在调用 getSize 函数取图片的宽、高时,React Native 框架事实上会下载这张图片,并且将该图片保存到缓存中。所以 getSize 函数也可以作为预加载图片资源的一个方法。
let imageSource = "http://www.hangge.com/blog/images/logo.png";
Image.getSize(imageSource).then((width, height) => {
  //取得图片的宽高,并进行相应的处理
  //......
}).catch((error) => {
  //下载图片失败
  console.log(error);
});

(2)prefetch()
我们也可以使用 Image 组件的静态函数 prefetch 来预下载某张网络图片。
let imageSource = "http://www.hangge.com/blog/images/logo.png";
Image.prefetch(imageSource).then((result) => {
  //当预下载成功时,返回值result是true
}).catch((error) => {
  //预下载图片失败
  console.log(error);
});


二、设置图像显示模式

1,resizeMode介绍

(1)当 Image 组件的实际宽、高与图片的实际宽、高不符时,要如何显示图片由样式定义中的 resizeMode 取值来决定。
(2)resizeMode 的五个取值分别是:containcoverstretchcenter repeat
  • 如果没有定义 resizeMode,默认值为:cover
  • 其中 repeat 只对 iOS 平台有效。
(3)无论 resizeMode 取值如何,图片都会在 Image 组件的显示区域居中显示。即显示的图片中点与显示区域的中点是一个点。
(4)resizeMode 比较特殊,可以按需要,自由放置在如下两个地方:
  • 既可以作为 Image 组件样式中的一个键值对发挥作用。
  • 也可以作为 Image 组建的属性来发挥作用。

2,各种模式介绍

(1)cover 模式(默认值)
该模式要求图片能够填充整个 Image 组件定义的显示区域,可以对图片进行放大或者缩小,可以丢弃放大或缩小后的图片中的部分区域,只求在显示比例不失真的情况下填充整个显示区域。
  • 如果图片的宽、高有一个值小于 Image 的实际宽、高, React Native 会对图片进行放大,直到图片的宽与高均不小于 Image 的实际宽、高。然后将放大的图片居中显示,超出显示区域的部分被直接丢弃。
  • 如果图片的宽、高均大于 Image 的实际宽、高, React Native 会对图片进行等比缩小,直到缩小后图片的宽、高有一个值等于 Image 的实际宽、高。然后将缩小后的图片居中显示,超出区域的部分被直接丢弃。

(2)contain 模式
该模式要求显示整张图片,可以对它进行等比放大或者缩小,但不能丢弃改变后图片的某部分。这个模式下图片得到完整的呈现,比例不会变。但图片可能无法填充 Image 的所有区域,会在侧边或者上下留下空白,由 Image 组件的底色填充。
  • 如果图片的实际宽、高都小于 Image 的实际宽、高, React Native 会对图片进行等比放大,直到宽、高中有一个值等于 Image 的实际宽、高。然后居中显示图片。
  • 如果图片的实际宽、高有一个值或者都大于 Image 的实际宽、高, React Native 会对图片进行等比缩小,直到缩小后图片的宽、高有一个不小于 Image 的实际宽、高,然后在 Image 中展现图片。

(3)stretch 模式
该模式要求图片填充整个 Image 定义的显示区域,因此会对图片进行任意的缩放,不考虑保持图片原来的宽、高比。这种模式显示出来的图片有可能会出现明显的失真。

(4)center 模式
该模式要求图片图片位于显示区域的中心。这种模式下图片可能也无法填充 Image 的所有区域,会在侧边或者上下留下空白,由 Image 组件的底色填充。
  • 如果图片的实际宽、高都小于 Image 的实际宽、高, React Native 不会对图片进行任何缩放,只是把它居中呈现在父 View 中。
  • 如果图片的实际宽、高有一个值或者都大于 Image 的实际宽、高, React Native 会对图片进行等比缩小,直到缩小后图片的宽、高有一个不小于 Image 的实际宽、高,然后在 Image 中展现图片。

(5)repeat 模式(iOS 独有)
该模式的图片处理思路是用一张或者多张图片来填充整个 Image 定义的显示区域。

三、Image 组件的事件属性

1,onLayout

虽然 Image 不是从 View 组件继承而来的,但它还是支持 onLayout 回调函数,使用方法也与 View 组件的 onLayout 函数类似。

2,onLoadStart、onLoad、onError、onLoadEnd

在通过 Image 组件读取并显示网络上的图片资源时,我们可以通过这四个属性来指定在开始读取与读取结束时所需要进行的函数处理。
  • onLoadStart:其指定的函数在开始读取图片时会被执行。
  • onLoad:其指定的函数只有在正确读取到图片资源时才会被执行。
  • onError:其指定的函数会在发生错误时被调用。
  • onLoadEnd:其指定的函数无论读取是否成功都会被执行。

四、网络图片的缓存策略

React Native 框架支持对网络图片的缓存,如果图片缓存到本地,以后一直使用这个缓存,不管服务器侧该文件是否发生改变。

1,使用样例

我们只需要在指定 Image 数据源时,在 source 属性中加入 cache 键以明确我们期望使用的图片缓存策略即可。
<Image style={styles.image} source={{
  uri: 'http://hangge.com/img.png',
  cache: 'force-cache'}} />

2,cache 可选值

  • default:使用平台默认策略
  • reload:数据将从原始地址加载,不使用现有的缓存数据。
  • force-cache:总是使用缓存数据,如果没有缓存,则从原始地址加载。
  • only-if-cached:总是使用缓存数据,如果没有缓存,则失败。

五、加载网络图片

1,效果图

这里实现一个简单的图片浏览器,通过点击下方的“上一张”和“下一张”按钮可以进行图片的切换。
         

2,代码说明

(1)Image 组件加载网络图片的方式是:source={uri: 'http://hangge.com/xxx.png'}
(2)Image 组件的默认大小是 0,是不显示图片的。我们需要给定图片的宽高或者知道图片的宽高比才能展示图片。
(3)我们将 Image 组件的图片适应模式设置为 resizeMode="contain",这样图片就会在指定大小内自适应缩放。

3,样例代码

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>
      );
    }
}

//默认应用的容器组件
class App extends Component {
    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,
  },
});

AppRegistry.registerComponent('HelloWorld', () => App);

六、加载本地图片

1,图片准备

假设我们在项目根目录下有个 image 文件夹,其内部放置了一些图片。

2,加载代码

(1)下面我们使用 Image 组件加载里面的"active.png"这张图片。
<Image source={require('./image/active.png')} />

(2)如果想根据状态来确定显示哪张图片,可以这么写。
var icon = this.props.active ? require('./image/active.png') : require('./image/inactive.png');
<Image source={icon} />

七、加载资源文件中的图片

React Native 也可以加载 Android 项目或者 iOS 项目中的图片资源文件。
注意React Native 加载资源文件中的图片时,使用的是不检查机制。也就是说,在编译代码时不会去检查资源图片是否真的存在,有可能发生在代码运行到需要取资源文件中的图片时,才发现图片不存在。这个在开发时要特别注意。

1,Android平台

下面代码我们加载 Android 平台下 mipmap/ic_launcher 这个资源图片。
import React, { Component } from 'react';
import {
 AppRegistry,
 StyleSheet,
 View,
 Image,
} from 'react-native';

//导入 nativeImageSource函数
let nativeImageSource = require('nativeImageSource');

class Main extends Component {
  render() {
    let ades = {
      android: 'mipmap/ic_launcher',
      width: 72,
      height: 72
    };

    return (
      <View style={styles.container}>
          <Image style={styles.image} source={nativeImageSource(ades)} />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {   //根View样式
      flex: 1,
      alignItems: 'center',
      backgroundColor: 'gray'
  },
  image: {
      backgroundColor: 'white',
      width: 100,
      height: 100,
  },
});

AppRegistry.registerComponent('HelloWorld', () => Main);

2,iOS平台

如果是 iOS 平台,将上面 render 函数中的 ades 变量改为如下即可:
let ades = {
  iOS: 'ic_launcher',
  width: 72,
  height: 72
};
评论

全部评论(0)

回到顶部