热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ReactNative调用Android相机图库

概述在很多的ReactNative开发中,我们需要调用原生的api实现调用相机和图库的功能,网上用的最多的开源库如:react-nativ

概述

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

调用Android图库相机

创建项目

执行命令 :

react-native init HeadImage

  • 1
  • 1

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

export default class HeadImage extends Component {render() {return (container}>this._clickImage}>'head_default'}} style={{width:50,height:50}}/>);}_clickImage(){console.log("click image...");}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

添加React Native和原生的交互

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

public class HeadImageModule extends ReactContextBaseJavaModule {public HeadImageModule(ReactApplicationContext reactContext) {super(reactContext);}@Overridepublic String getName() {return "HeadImageModule"; //注意这里的返回值}@ReactMethodpublic void callCamera() { // 调用相机的方法Log.d("","call camera...");}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

HeadImagePackage.java

public class HeadImagePackage implements ReactPackage {&#64;Overridepublic List createNativeModules(ReactApplicationContext reactContext) {List modules &#61; new ArrayList<>();modules.add(new HeadImageModule(reactContext));return modules;}&#64;Overridepublic List<Classextends JavascriptModule>> createJSModules() {return Collections.emptyList();}&#64;Overridepublic List createViewManagers(ReactApplicationContext reactContext) {return Collections.emptyList();}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在MainApplication注册模块 
MainApplication.java

&#64;Override
protected List getPackages() {return Arrays.asList(new MainReactPackage(),new HeadImagePackage() //注册模块);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

js调用Java代码

在index.android.js的_clickImage方法调用Java方法。代码如下&#xff1a;

_clickImage(){NativeModules.HeadImageModule.callCamera()
}

  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

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

/ 保存图片的sd卡路径
private static final String HEAD_IMAGE_PATH &#61; Environment.getExternalStorageDirectory().getAbsolutePath() &#43; "/HeadImage/";
// 保存图片的名称
private static final String HEAD_IMAGE_NAME &#61; "head_image.png";// startActivityForResult 的 requestCode
private static final int REQUEST_CODE_CAMERA &#61; 0;
private static final int REQUEST_CODE_GALLERY &#61; 1;
private static final int REQUEST_CODE_CROP &#61; 2;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

接下来实现callCamera方法&#xff08;注&#xff1a;要让js可以调用必须加&#64;ReactMethod&#xff0c;Promise&#xff09;&#xff0c;callCamera相关代码如下&#xff1a;

&#64;ReactMethod
public void callCamera(Promise promise) {recursionDeleteFile(); // 删除目录下除了头像图片的其他临时图片Intent intent &#61; new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//启动相机的intentif (isPathExists()) { // 判断常量定义的路径是否存在&#xff0c;不存在就创建&#xff0c;然后返回truemFullPath &#61; HEAD_IMAGE_PATH &#43; System.currentTimeMillis() &#43; ".png"; // 临时图片mUri &#61; Uri.fromFile(new File(mFullPath));intent.putExtra(MediaStore.EXTRA_OUTPUT, mUri);Activity activity &#61; getCurrentActivity();if (activity !&#61; null) {mPromise &#61; promise;activity.startActivityForResult(intent, REQUEST_CODE_CAMERA);}}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

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

reactContext.addActivityEventListener(new BaseActivityEventListener() {&#64;Overridepublic void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {if (requestCode &#61;&#61; REQUEST_CODE_CAMERA) { // 调用相机回调if (resultCode &#61;&#61; Activity.RESULT_OK) { // *************1.拍照完成&#xff0c;将进入裁剪界面activity.startActivityForResult(cropImage(mUri), REQUEST_CODE_CROP);// 启动裁剪界面} else if (resultCode &#61;&#61; Activity.RESULT_CANCELED) { // 拍照界面点击取消mPromise.resolve(null);// mFullPath就是callCamera里面定义的临时图片路径// 如果没有取消拍照&#xff0c;那么就不执行这里&#xff0c;临时图片的删除将在下次调用相机的时候&#xff0c;所以与recursionDeleteFile()不重复new File(mFullPath).delete();}} else if (requestCode &#61;&#61; REQUEST_CODE_CROP) { // ************2.裁剪完成if (resultCode &#61;&#61; Activity.RESULT_OK) {// uri存的是临时图片路径&#xff0c;返回给js代码&#xff0c;这里有个问题&#xff0c;稍后再说mPromise.resolve(mUri.toString());// 将临时图片复制一份&#xff0c;保存为最终的头像图片saveHeadImage();} else if (resultCode &#61;&#61; Activity.RESULT_CANCELED) {mPromise.resolve(null);new File(mFullPath).delete();}}}
});

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

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

if (resultCode &#61;&#61; Activity.RESULT_OK) {mPromise.resolve(mUri.toString());// 将临时图片复制一份&#xff0c;保存为最终的头像图片saveHeadImage();}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

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

import React, {Component, PropTypes} from &#39;react&#39;;
import {View,StyleSheet,Image,NativeModules,
} from &#39;react-native&#39;;export default class MyImage extends Component {constructor(props) {super(props);this.state &#61; {uri: null,};}static defaultProps &#61; {uri: null,};static propTypes &#61; {uri: PropTypes.string,imageStyle: PropTypes.oneOfType([PropTypes.number, PropTypes.object]),}async componentWillReceiveProps() {let isExists &#61; await NativeModules.HeadImageModule.isImageExists();if (this.props.uri !&#61;&#61; null) {this.setState({uri: this.props.uri});} else if (isExists) {this.setState({uri: await NativeModules.HeadImageModule.getImageUri()});} else {this.setState({uri: &#39;head_default&#39;});}}render() {return (this.state.uri}} style&#61;{this.props.imageStyle}/>);}}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

修改index.android.js代码&#xff1a;

export default class HeadImage extends Component {constructor(props) {super(props);this.state &#61; {headImageUri: null,};}render() {return (container}>this._clickImage.bind(this)}>this.state.headImageUri} imageStyle&#61;{{width: 100,height: 100}}/>);}async _clickImage() {this.setState({headImageUri: await NativeModules.HeadImageModule.callCamera() // 相机拍照// headImageUri: await NativeModules.HeadImageModule.callGallery() // 相册选择图片});}componentDidMount() {this.setState({code: this.props.code});}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

附&#xff1a;源码


推荐阅读
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 本文详细介绍了解决全栈跨域问题的方法及步骤,包括添加权限、设置Access-Control-Allow-Origin、白名单等。通过这些操作,可以实现在不同服务器上的数据访问,并解决后台报错问题。同时,还提供了解决second页面访问数据的方法。 ... [详细]
  • 展开全部下面的代码是创建一个立方体Thisexamplescreatesanddisplaysasimplebox.#Thefirstlineloadstheinit_disp ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • 使用eclipse创建一个Java项目的步骤
    本文介绍了使用eclipse创建一个Java项目的步骤,包括启动eclipse、选择New Project命令、在对话框中输入项目名称等。同时还介绍了Java Settings对话框中的一些选项,以及如何修改Java程序的输出目录。 ... [详细]
  • EPPlus绘制刻度线的方法及示例代码
    本文介绍了使用EPPlus绘制刻度线的方法,并提供了示例代码。通过ExcelPackage类和List对象,可以实现在Excel中绘制刻度线的功能。具体的方法和示例代码在文章中进行了详细的介绍和演示。 ... [详细]
  • ReactJSUIAnt设计空组件原文:https://w ... [详细]
  • 使用PhpStorm或WebStorm作为electron IDE
    最近在研究electron,考虑到以前一直用PhpStorm做开发,而且electron就是基于nodejs的,因此很自然的想到要继续用PhpStorm做IDE。开发打开RunDe ... [详细]
  • mac goland激活码[最新免费获取]
    (mac goland激活码)JetBrains旗下有多款编译器工具(如:IntelliJ、WebStorm、PyCharm等)在各编程领域几乎都占据了垄断地位。建立在开源Inte ... [详细]
author-avatar
心窝子难受呢
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有