React Native调用Android相机图库

前端之家收集整理的这篇文章主要介绍了React Native调用Android相机图库前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

概述

在很多的React Native开发中,我们需要调用原生的api实现调用相机和图库的功能,网上用的最多的开源库如:react-native-image-picker。关于react-native-image-picker的用法大家请看相关的文档。我们今天手动实现一份。

调用Android图库相机

创建项目

执行命令 :

  1. react-native init HeadImage

创建一个名为HeadImage的工程,可以使用命令先运行下Demo项目。
然后照一张图片,放到放到工程的 HeadImage\Android\app\src\main\res\drawable 目录下。然后打开webstorm选择工程根目录,修改index.android.js代码如下:

  1. export default class HeadImage extends Component {
  2. render() {
  3. return (
  4. <View style={styles.container}>
  5. <TouchableOpacity onPress={this._clickImage}>
  6. <Image source={{uri: 'head_default'}} style={{width:50,height:50}}/>
  7. </TouchableOpacity>
  8. </View>
  9. );
  10. }
  11.  
  12. _clickImage(){
  13. console.log("click image...");
  14. }
  15. }

添加React Native和原生的交互

新建两个类,HeadImageModule.Java和HeadImagePackage.java,分别继承ReactContextBaseJavaModule和ReactPackage,之后在MainApplication.java里面注册代码如下:
HeadImageModule.java

  1. public class HeadImageModule extends ReactContextBaseJavaModule {
  2. public HeadImageModule(ReactApplicationContext reactContext) {
  3. super(reactContext);
  4. }
  5. @Override
  6. public String getName() {
  7. return "HeadImageModule"; //注意这里的返回值
  8. }
  9. @ReactMethod
  10. public void callCamera() { // 调用相机的方法
  11. Log.d("","call camera...");
  12. }
  13. }

HeadImagePackage.java

  1. public class HeadImagePackage implements ReactPackage { @Override public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { List<NativeModule> modules = new ArrayList<>(); modules.add(new HeadImageModule(reactContext)); return modules; } @Override public List<Class<? extends JavaScriptModule>> createJSModules() { return Collections.emptyList(); } @Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Collections.emptyList(); } }

在MainApplication注册模块
MainApplication.java

  1. @Override
  2. protected List<ReactPackage> getPackages() {
  3. return Arrays.<ReactPackage>asList(
  4. new MainReactPackage(),new HeadImagePackage() //注册模块
  5. );
  6. }

js调用Java代码

在index.android.js的_clickImage方法调用Java方法代码如下:

  1. _clickImage(){
  2. NativeModules.HeadImageModule.callCamera()
  3. }

注:别忘了导包:import { NativeModules } from ‘react-native’;
到这里已经实现了js与原生的交互,接下来我们需要实现调用相机的具体逻辑了。在HeadImageModule.java里我们先定义几个常量:

  1. / 保存图片sd卡路径
  2. private static final String HEAD_IMAGE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/HeadImage/";
  3. // 保存图片名称
  4. private static final String HEAD_IMAGE_NAME = "head_image.png";
  5.  
  6. // startActivityForResult 的 requestCode
  7. private static final int REQUEST_CODE_CAMERA = 0;
  8. private static final int REQUEST_CODE_GALLERY = 1;
  9. private static final int REQUEST_CODE_CROP = 2;

接下来实现callCamera方法(注:要让js可以调用必须加@ReactMethod,Promise),callCamera相关代码如下:

  1. @ReactMethod
  2. public void callCamera(Promise promise) {
  3. recursionDeleteFile(); // 删除目录下除了头像图片的其他临时图片
  4. Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//启动相机的intent
  5. if (isPathExists()) { // 判断常量定义的路径是否存在,不存在就创建,然后返回true
  6. mFullPath = HEAD_IMAGE_PATH + System.currentTimeMillis() + ".png"; // 临时图片
  7. mUri = Uri.fromFile(new File(mFullPath));
  8. intent.putExtra(MediaStore.EXTRA_OUTPUT,mUri);
  9. Activity activity = getCurrentActivity();
  10. if (activity != null) {
  11. mPromise = promise;
  12. activity.startActivityForResult(intent,REQUEST_CODE_CAMERA);
  13. }
  14. }
  15. }

执行完这个方法就可以启动相机了,但是这样每次调用相机都会创建一个临时图片,为了不使sd卡存头像图片文件夹越来越大,所以编写了recursionDeleteFile()方法每次做一次递归删除删除临时图片。拍照点击完成之后,就该去onActivityResult里面处理了,rn提供了一个接口实现监听onActivityResult,在HeadImageModule.java构造方法里面添加如下代码

  1. reactContext.addActivityEventListener(new BaseActivityEventListener() {
  2. @Override
  3. public void onActivityResult(Activity activity,int requestCode,int resultCode,Intent data) {
  4. if (requestCode == REQUEST_CODE_CAMERA) { // 调用相机回调
  5. if (resultCode == Activity.RESULT_OK) { // *************1.拍照完成,将进入裁剪界面
  6. activity.startActivityForResult(cropImage(mUri),REQUEST_CODE_CROP);// 启动裁剪界面
  7. } else if (resultCode == Activity.RESULT_CANCELED) { // 拍照界面点击取消
  8. mPromise.resolve(null);
  9. // mFullPath就是callCamera里面定义的临时图片路径
  10. // 如果没有取消拍照,那么就不执行这里,临时图片删除将在下次调用相机的时候,所以与recursionDeleteFile()不重复
  11. new File(mFullPath).delete();
  12. }
  13. } else if (requestCode == REQUEST_CODE_CROP) { // ************2.裁剪完成
  14. if (resultCode == Activity.RESULT_OK) {
  15. // uri存的是临时图片路径,返回给js代码,这里有个问题,稍后再说
  16. mPromise.resolve(mUri.toString());
  17. // 将临时图片复制一份,保存为最终的头像图片
  18. saveHeadImage();
  19. } else if (resultCode == Activity.RESULT_CANCELED) {
  20. mPromise.resolve(null);
  21. new File(mFullPath).delete();
  22. }
  23. }
  24. }
  25. });

拍照完成之后就是本地裁剪图片了,这里不再讲解,后面大家直接看代码。裁剪完成之后,返回给js的图片是临时图片,而不是saveHeadImage()保存最终图片之后返回最终的图片。这里我们需要手动保存一份图片代码如下:

  1. if (resultCode == Activity.RESULT_OK) {
  2. mPromise.resolve(mUri.toString());
  3. // 将临时图片复制一份,保存为最终的头像图片
  4. saveHeadImage();
  5. }

到这里,头像图片已经成功的保存到sd卡上了,接下来就是js显示的实现了,js需要处理的图片包括三个:默认头像,sd卡存的临时头像,sd卡存的最终头像,至于显示的时候我们先取最终头像,然后取临时头像。
新建MyImage.js

  1. import React,{Component,PropTypes} from 'react';
  2. import {
  3. View,StyleSheet,Image,NativeModules,} from 'react-native';
  4.  
  5. export default class MyImage extends Component {
  6.  
  7. constructor(props) {
  8. super(props);
  9. this.state = {
  10. uri: null,};
  11. }
  12.  
  13. static defaultProps = {
  14. uri: null,};
  15.  
  16. static propTypes = {
  17. uri: PropTypes.string,imageStyle: PropTypes.oneOfType([PropTypes.number,PropTypes.object]),}
  18.  
  19. async componentWillReceiveProps() {
  20. let isExists = await NativeModules.HeadImageModule.isImageExists();
  21. if (this.props.uri !== null) {
  22. this.setState({
  23. uri: this.props.uri
  24. });
  25. } else if (isExists) {
  26. this.setState({
  27. uri: await NativeModules.HeadImageModule.getImageUri()
  28. });
  29. } else {
  30. this.setState({
  31. uri: 'head_default'
  32. });
  33. }
  34. }
  35.  
  36. render() {
  37. return (
  38. <Image source={{uri: this.state.uri}} style={this.props.imageStyle}/>
  39. );
  40. }
  41.  
  42. }

修改index.android.js代码

  1. export default class HeadImage extends Component {
  2.  
  3. constructor(props) {
  4. super(props);
  5. this.state = {
  6. headImageUri: null,};
  7. }
  8.  
  9. render() {
  10. return (
  11. <View style={styles.container}>
  12. <TouchableOpacity onPress={this._clickImage.bind(this)}>
  13. <MyImage uri={this.state.headImageUri} imageStyle={{width: 100,height: 100}}/>
  14. </TouchableOpacity>
  15. </View>
  16. );
  17. }
  18.  
  19. async _clickImage() {
  20. this.setState({
  21. headImageUri: await NativeModules.HeadImageModule.callCamera() // 相机拍照
  22. // headImageUri: await NativeModules.HeadImageModule.callGallery() // 相册选择图片
  23. });
  24. }
  25.  
  26. componentDidMount() {
  27. this.setState({
  28. code: this.props.code
  29. });
  30. }
  31. }

附:源码

猜你在找的React相关文章