react-native中CameraRoll模塊提供了訪問本地相冊的功能。javascript
在react版本爲0.23.0的項目中,不支持Android,並且在iOS中使用CameraRoll還須要咱們手動操做:java
iOS:node
通過這樣的添加咱們在項目中再使用CameraRoll裏邊的函數就不會出錯了。react
CameraRoll模塊中有兩個函數:saveImageWithTag()、getPhotos()。android
保存一個圖片到相冊。express
@param {string} tag 在安卓上,本參數是一個本地URI,例如"file:///sdcard/img.png"
.react-native
在iOS設備上多是如下之一:api
返回一個Promise,操做成功時返回新的URI。xcode
示例:app
CameraRoll.saveImageWithTag(image).then(function (success) { Alert.alert( '', '保存到相冊成功', [ {text: '肯定', onPress: () => console.log(success)} ] ) }, function (error) { Alert.alert( '', '保存到相冊失敗', [ {text: '肯定', onPress: () => console.log(error)} ] ) } ) }
學習這個功能是在官方demo中學習的,它寫成了一個能夠使用的js文件CameraRollView.js,咱們須要將該文件引入咱們的項目中。
CameraRollView.js文件代碼:
/** * The examples provided by Facebook are for non-commercial testing and * evaluation purposes only. * * Facebook reserves all rights not expressly granted. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * @providesModule CameraRollView * @flow */ 'use strict'; var React = require('react'); var ReactNative = require('react-native'); var { ActivityIndicatorIOS, CameraRoll, Image, ListView, Platform, StyleSheet, TouchableOpacity, View, } = ReactNative; var groupByEveryN = require('groupByEveryN'); var logError = require('logError'); var propTypes = { /** * The group where the photos will be fetched from. Possible * values are 'Album', 'All', 'Event', 'Faces', 'Library', 'PhotoStream' * and SavedPhotos. */ groupTypes: React.PropTypes.oneOf([ 'Album', 'All', 'Event', 'Faces', 'Library', 'PhotoStream', 'SavedPhotos', ]), /** * Number of images that will be fetched in one page. */ batchSize: React.PropTypes.number, /** * A function that takes a single image as a parameter and renders it. */ renderImage: React.PropTypes.func, /** * imagesPerRow: Number of images to be shown in each row. */ imagesPerRow: React.PropTypes.number, /** * The asset type, one of 'Photos', 'Videos' or 'All' */ assetType: React.PropTypes.oneOf([ 'Photos', 'Videos', 'All', ]), }; var CameraRollView = React.createClass({ propTypes: propTypes, getDefaultProps: function(): Object { return { groupTypes: 'SavedPhotos', batchSize: 5, imagesPerRow: 1, assetType: 'Photos', renderImage: function(asset) { var imageSize = 150; var imageStyle = [styles.image, {width: imageSize, height: imageSize}]; return ( <Image source={asset.node.image} style={imageStyle} /> ); }, }; }, getInitialState: function() { var ds = new ListView.DataSource({rowHasChanged: this._rowHasChanged}); return { assets: ([]: Array<Image>), groupTypes: this.props.groupTypes, lastCursor: (null : ?string), assetType: this.props.assetType, noMore: false, loadingMore: false, dataSource: ds, }; }, /** * This should be called when the image renderer is changed to tell the * component to re-render its assets. */ rendererChanged: function() { var ds = new ListView.DataSource({rowHasChanged: this._rowHasChanged}); this.state.dataSource = ds.cloneWithRows( groupByEveryN(this.state.assets, this.props.imagesPerRow) ); }, componentDidMount: function() { this.fetch(); }, componentWillReceiveProps: function(nextProps: {groupTypes?: string}) { if (this.props.groupTypes !== nextProps.groupTypes) { this.fetch(true); } }, _fetch: function(clear?: boolean) { if (clear) { this.setState(this.getInitialState(), this.fetch); return; } var fetchParams: Object = { first: this.props.batchSize, groupTypes: this.props.groupTypes, assetType: this.props.assetType, }; if (Platform.OS === "android") { // not supported in android delete fetchParams.groupTypes; } if (this.state.lastCursor) { fetchParams.after = this.state.lastCursor; } CameraRoll.getPhotos(fetchParams) .then((data) => this._appendAssets(data), (e) => logError(e)); }, /** * Fetches more images from the camera roll. If clear is set to true, it will * set the component to its initial state and re-fetch the images. */ fetch: function(clear?: boolean) { if (!this.state.loadingMore) { this.setState({loadingMore: true}, () => { this._fetch(clear); }); } }, render: function() { return ( <View style={{flexWrap: 'wrap'}}> <ListView contentContainerStyle={{flex:1, flexDirection:'row',flexWrap: 'wrap', justifyContent:'center'}} renderRow={this._renderRow} renderFooter={this._renderFooterSpinner} onEndReached={this._onEndReached} style={{flex:1}} dataSource={this.state.dataSource} /> </View> ); }, _rowHasChanged: function(r1: Array<Image>, r2: Array<Image>): boolean { if (r1.length !== r2.length) { return true; } for (var i = 0; i < r1.length; i++) { if (r1[i] !== r2[i]) { return true; } } return false; }, _renderFooterSpinner: function() { if (!this.state.noMore) { return <ActivityIndicatorIOS style={styles.spinner} />; } return null; }, // rowData is an array of images _renderRow: function(rowData: Array<Image>, sectionID: string, rowID: string) { var images = rowData.map((image) => { if (image === null) { return null; } return this.props.renderImage(image); }); return ( <View> {images} </View> ); }, _appendAssets: function(data: Object) { var assets = data.edges; var newState: Object = { loadingMore: false }; if (!data.page_info.has_next_page) { newState.noMore = true; } if (assets.length > 0) { newState.lastCursor = data.page_info.end_cursor; newState.assets = this.state.assets.concat(assets); newState.dataSource = this.state.dataSource.cloneWithRows( groupByEveryN(newState.assets, this.props.imagesPerRow) ); } this.setState(newState); }, _onEndReached: function() { if (!this.state.noMore) { this.fetch(); } }, }); var styles = StyleSheet.create({ image: { margin: 4, }, }); module.exports = CameraRollView;
文件打開會有錯誤顯示,只是語法不同,這個不影響效果。
使用方法:
import CameraRollView from '../CameraRollView'; export default class CameraRollView extends Component { constructor(props) { super(props); CameraRoll.getPhotos({ first: 21, assetType: 'Photos' }).then(function (data) { }, function (error) { }) } _renderImage(asset) { var windowSize = require('Dimensions').get('window'); return ( <TouchableOpacity key={asset}> <Image source={asset.node.image} style={{width: (windowSize.width-30)/3, height: 110, margin:5}}/> </TouchableOpacity> ); } render() { return (<View style={{flex:1}}> <CameraRollView renderImage={this._renderImage}/> </View> ) } }