Camera Roll API + Upload From Camera Roll Module
我们将介绍使用内置的React Native Camera Roll API显示相机中的图片。一旦用户选择了一张图片,我们将使用
Upload From Camera Roll Module获得图片的base64数据。如果你只是想让用户看到和选择图片,你可以使用这种方法,但如果是想拍照,你需要使用
camera模块. 如果不想让用户定义和选择图片的界面,你可以使用
Image Picker Module.
导入CameraRoll API
const React = require('react-native'); const { CameraRoll,} = React;
CameraRoll.getPhotos接受 3 个参数:第一个参数是一个对像,它定义了从相机胶卷中返回什么样的图片。第二个是一个回调函数,这个函数,接受请求到的图片,第三个参数也是一个回调函数,它用来处理错误。首先,让我们看看第一个参数,它是如何定义要返回的图片。以下是这个对数的属性。
{ first: ...,// (必须的) 在照片中,按反相排序后,在获取的照片的数量 after: ...,// 上一次调用getPhotos返回的指针。cursor groupTypes: ...,// 指定分组类型,过滤结果 // One of ['Album','All','Event','Faces','Library','PhotoStream','SavedPhotos'(default)] groupName: ...,// Specifies filter on group names,like 'Recent Photos' or custom album titles assetType: ... // Specifies filter on assetType // One of ['All','Videos','Photos'(default)] }
const fetchParams = { first: 25,}
{ edges: [ node: { type: ...,group_name: ...,image: { uri: ...,height: ...,width: ...,isStored: ...,},timestamp: ...,location { ... },node: { ... },... ],page_info: { has_next_page: ...,start_cursor: ...,end_cursor: ...,} }
由于节点中的image对像包含了我们将要在App中显示图片的时要使用到的数据,所以我们需要创建一个函数,从edges数组中提取image对像。并且应该将它们保存到一个state变量中.
storeImages(data) { const assets = data.edges; const images = assets.map( asset => asset.node.image ); this.setState({ images: images,}); },
由于我们使用了images变量,所以需要先定义这个变量
logImageError(err) { console.log(err); },
到目前为此,我们已经为CameraRoll.getPhotos定义了三个参数。我们将在ComponentDidMount()中调用这个getPhotos,它会检索一次图片信息。
componentDidMount() { const fetchParams = { first: 25,}; CameraRoll.getPhotos(fetchParams,this.storeImages,this.logImageError); },
读取图片
让我们先导入StyleSheet和Image组件
render() { return ( <ScrollView style={styles.container}> <View style={styles.imageGrid}> { this.state.images.map(image => <Image style={styles.image} source={{ uri: image.uri }} />) } </View> </ScrollView> ); }
然后添加样式
const styles = StyleSheet.create({ container: { flex: 1,backgroundColor: '#F5FCFF',imageGrid: { flex: 1,flexDirection: 'row',flexWrap: 'wrap',justifyContent: 'center' },image: { width: 100,height: 100,margin: 10,});
到目前为此,你的组件看起来如下
const React = require('react-native'); const { StyleSheet,Text,View,ScrollView,CameraRoll,} = React; const styles = StyleSheet.create({ container: { flex: 1,imageGrid: { flex: 1,justifyContent: 'center' },image: { width: 100,}); const reactImageProject = React.createClass({ getInitialState() { return { images: [],}; },componentDidMount() { const fetchParams = { first: 25,this.logImageError); },storeImages(data) { const assets = data.edges; const images = assets.map((asset) => asset.node.image); this.setState({ images: images,}); },logImageError(err) { console.log(err); },render() { return ( <ScrollView style={styles.container}> <View style={styles.imageGrid}> { this.state.images.map((image) => <Image style={styles.image} source={{ uri: image.uri }} />) } </View> </ScrollView> ); } });
当你运行这个项目,你会看到一个最新相机中最新的25张图片
选择图片
我们首先测试选择到图片的uri
selectImage(uri) { this.setState({ selected: uri,}); console.log('Selected image: ',uri); },
const { StyleSheet,TouchableHighlight,} = React; render() { return ( <ScrollView style={styles.container}> <View style={styles.imageGrid}> { this.state.images.map((image) => { return ( <TouchableHighlight onPress={this.selectImage.bind(null,image.uri)}> <Image style={styles.image} source={{ uri: image.uri }} /> </TouchableHighlight> ); }) } </View> </ScrollView> ); }
获得图片的base64数据
已经存在一个模块,它使用React native image 组件获得这个图片的base64版本。但它不能通过NPM安装。所以我们仅要在创建自定义模块是,将它添加进来。如
upload-from-camera-roll中有介绍,如何在你的项目中包含upload-form-camera-roll模块。
selectImage(uri) { NativeModules.ReadImageData.readImage(uri,(image) => { this.setState({ selected: image,}); console.log(image); }); },
const React = require('react-native'); const { AppRegistry,NativeModules,} = React; const styles = StyleSheet.create({ container: { flex: 1,} }); const reactImageProject = React.createClass({ getInitialState() { return { images: [],}; },componentDidMount() { const fetchParams = { first: 25,}; CameraRoll.getPhotos(fetchParams,this.logImageError); },storeImages(data) { const assets = data.edges; const images = assets.map((asset) => asset.node.image); this.setState({ images: images,}); },logImageError(err) { console.log(err); },selectImage(uri) { NativeModules.ReadImageData.readImage(uri,(image) => { this.setState({ selected: image,}); console.log(image); }); },render() { return ( <ScrollView style={styles.container}> <View style={styles.imageGrid}> { this.state.images.map((image) => { return ( <TouchableHighlight onPress={this.selectImage.bind(null,image.uri)}> <Image style={styles.image} source={{ uri: image.uri }} /> </TouchableHighlight> ); }) } </View> </ScrollView> ); } }); AppRegistry.registerComponent('reactImageProject',() => reactImageProject);
关于NativeModules模块
我们可以在获取到的图片数据中,添加一个base64属性到image对像. 如下
在Xcode中打开Libraries > RCTImage > RCTCameraRollManager.m中打开
替换这个文件为
打开/node_modules/react-native/Libraries/CameraRoll/CameraRoll.js,将下面的行,添加到76行
为了更好的优化,我们创建一个自定义的本地模块,它充许我们的Javascript 与Object-c通话,通过这种方式,我们给 Object-C传递一个图片资源的URI给它,Object-c在返回这个图片的base64数据。现在iOS仅在需要的时候读取一个图片。相对于上面的方法,要读取所有的图片。这是一个非常大的优化 。
创建一个自定义模块,非常简单。
在Xcode中,打开Project > Libraries > React > Base. 在Base上右键,选择New File... ,在选择Object-C文件。命名为RCTCustom.m,并且添加以下的内容。这就创建了一个ReadImageData的模块了.
#import "RCTBridgeModule.h" #import <AssetsLibrary/AssetsLibrary.h> #import <UIKit/UIKit.h> @interface ReadImageData : NSObject <RCTBridgeModule> @end @implementation ReadImageData RCT_EXPORT_MODULE(); RCT_EXPORT_METHOD(readImage:(NSString *)input callback:(RCTResponseSenderBlock)callback) { // Create NSURL from uri NSURL *url = [[NSURL alloc] initWithString:input]; // Create an ALAssetsLibrary instance. This provides access to the // videos and photos that are under the control of the Photos application. ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; // Using the ALAssetsLibrary instance and our NSURL object open the image. [library assetForURL:url resultBlock:^(ALAsset *asset) { // Create an ALAssetRepresentation object using our asset // and turn it into a bitmap using the CGImageRef opaque type. CGImageRef imageRef = [asset thumbnail]; // Create UIImageJPEGRepresentation from CGImageRef NSData *imageData = UIImageJPEGRepresentation([UIImage imageWithCGImage:imageRef],0.1); // Convert to base64 encoded string NSString *base64Encoded = [imageData base64EncodedStringWithOptions:0]; callback(@[base64Encoded]); } failureBlock:^(NSError *error) { NSLog(@"that didn't work %@",error); }]; } @end
现在你的Xcode project 已经有了一个新的自定义模块,我们可以在Javascript中导入这个组件.
var {View,NativeModules} = React;
然后我们可以能过NativeModules访问我们 new module
NativeModules.ReadImageData.readImage(ourImage.node.image.uri,(image) => { console.log(image) })
然后,能过fetch方法,上传图片资源
fetch('http://your.server/app.PHP',{ method:'POST',headers: { 'Accept': 'application/json','Content-Type': 'application/json',body: JSON.stringify({imageData:image}) } })