本文共 19194 字,大约阅读时间需要 63 分钟。
从网上看了很多关于react native实现条码扫描的文章,里面出现了很多第三方库,有的文章说react-native-camera不能支持Android,我就自己试着写写,发现他可以兼容ios和Android。下面就来看看怎么实现吧~http://www.bijishequ.com/detail/379217?p=20
首先打开终端,在相应的目录下输入命令创建新项目
react-native init CameraDemo
项目创建完成,进入项目根目录下输入命令下载react-native-camera库
1.npm install react-native-camera@https://github.com/lwansbrough/react-native-camera.git --save2.react-native link react-native-camera
1.打开android/app/src/main/java/[...]/MainApplication.java文件,添加import com.lwansbrough.RCTCamera.RCTCameraPackage;
,在getPackages()方法里添加new RCTCameraPackage(),
2.打开android/settings.gradle文件,添加
include ':react-native-camera'project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
3.打开android/app/build.gradle文件,在dependencies{}中添加compile project(':react-native-camera'
4.在AndroidManifest.xml配置文件中添加相关权限:
//相机权限 //震动权限
注:android配置的前三个步骤一般情况下会自动添加,若没有添加,按上述步骤手动添加!
1.使用Xcode打开CameraDemo/ios/CameraDemo.xcodeproj文件,在Project navigator->Libraries文件夹上右击选择Add Files to 'CameraDemo';
2.选择项目中的node_modules->react-native-camera并且添加RCTCamera.xcodeproj文件;
3.在Build Phases中添加libRCTCamera.a;
4.在Build Settings中找到Search Paths下的Header Search Paths,添加$(SRCROOT)/../../react-native/React和$(SRCROOT)/../../../React,并且选择recursive;
如下图:
5.打开ScanDemo/ios/ScanDemo/Info.plist文件,添加下列权限
NSCameraUsageDescription 请允许使用您的相机 NSLocationWhenInUseUsageDescription NSPhotoLibraryUsageDescription 请允许打开您的相册
注:ios中前三个步骤也会自动加载,若没有添加,需按上述步骤手动添加!
1.scan.js代码
import React, { Component } from 'react';import { connect } from 'react-redux';import { View, Text, StyleSheet, Image, Platform, Vibration, TouchableOpacity, Animated, Easing, Dimensions} from 'react-native';const {width, height} = Dimensions.get('window');import {ToastMessage} from '../../utils/toast';import Camera from 'react-native-camera';import ViewFinder from '../../components/order/viewFinder';import backIcon from '../../../assets/img/backIcon.png';//返回按钮import scanLine from '../../../assets/img/scan_line.png';//扫描线export default class Scan extends Component { constructor(props) { super(props); this.camera = null; this.state = { transCode:'',//条码 openFlash: false, active: true, flag:true, fadeInOpacity: new Animated.Value(0), // 初始值 isEndAnimation:false,//结束动画标记 } this._goBack = this._goBack.bind(this); this._startAnimation = this._startAnimation.bind(this); this.barcodeReceived = this.barcodeReceived.bind(this); this._search = this._search.bind(this); this._changeFlash = this._changeFlash.bind(this); this.changeState = this.changeState.bind(this); } componentDidMount() { this._startAnimation(false); } //开始动画,循环播放 _startAnimation(isEnd) { Animated.timing(this.state.fadeInOpacity, { toValue: 1, duration: 3000, easing: Easing.linear }).start( () => { if (isEnd){ this.setState({ isEndAnimation:true }) return; } if (!this.state.isEndAnimation){ this.state.fadeInOpacity.setValue(0); this._startAnimation(false) } } ); console.log("开始动画"); } barcodeReceived(e) { if (e.data !== this.transCode) { Vibration.vibrate([0, 500, 200, 500]); this.transCode = e.data; // 放在this上,防止触发多次,setstate有延时 if(this.state.flag){ this.changeState(false); //通过条码编号获取数据 } console.log("transCode="+this.transCode); } } //返回按钮点击事件 _goBack() { this.setState({ isEndAnimation:true, }); this.props.navigator.pop(); } //开灯关灯 _changeFlash() { this.setState({ openFlash: !this.state.openFlash, }); } //改变请求状态 changeState(status){ this.setState({ flag:status }); console.log('status='+status); } render(){ const { openFlash, active, } = this.state; return({(() => { if (active) { return ( ) }}const styles =StyleSheet.create({ allContainer:{ flex:1, }, container: { ...Platform.select({ ios: { height: 64, }, android: { height: 50 } }), backgroundColor:BLACK_COLOR, opacity:0.5 }, titleContainer: { flex: 1, ...Platform.select({ ios: { paddingTop: 15, }, android: { paddingTop: 0, } }), flexDirection: 'row', }, leftContainer: { flex:0, justifyContent: 'center', }, backImg: { marginLeft: 10, }, cameraStyle: { alignSelf: 'center', width: width, height: height, }, flash: { flexDirection: 'column', alignItems: 'center', justifyContent: 'flex-start', marginTop: 60, }, flashIcon: { fontSize: 1, color: WHITE_COLOR, }, text: { fontSize: 14, color: WHITE_COLOR, marginTop:5 }, icon:{ color:WHITE_COLOR, fontSize:20, fontFamily:'iconfont' }, scanLine:{ alignSelf:'center', }, centerContainer:{ ...Platform.select({ ios: { height: 80, }, android: { height: 60, } }), width:width, backgroundColor:BLACK_COLOR, opacity:0.5 }, bottomContainer:{ alignItems:'center', backgroundColor:BLACK_COLOR, alignSelf:'center', opacity:0.5, flex:1, width:width }, fillView:{ width:(width-220)/2, height:220, backgroundColor:BLACK_COLOR, opacity:0.5 }, scan:{ width:220, height:220, alignSelf:'center' }})this.camera = cam} style={styles.cameraStyle} barcodeScannerEnabled={true} onBarCodeRead={ this.barcodeReceived } torchMode={openFlash ? 'on' : 'off'}> ); } })()}将运单上的条码放入框内即可自动扫描。 开灯/关灯
2.viewFinder.js代码
import React, { Component, PropTypes,} from 'react';import { ActivityIndicator, StyleSheet, View,} from 'react-native';const styles = StyleSheet.create({ container: { alignItems: 'center', justifyContent: 'center', position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, }, viewfinder: { alignItems: 'center', justifyContent: 'center', backgroundColor: 'transparent', }, topLeftEdge: { position: 'absolute', top: 0, left: 0, }, topRightEdge: { position: 'absolute', top: 0, right: 0, }, bottomLeftEdge: { position: 'absolute', bottom: 0, left: 0, }, bottomRightEdge: { position: 'absolute', bottom: 0, right: 0, },});class Viewfinder extends Component { constructor(props) { super(props); this.getBackgroundColor = this.getBackgroundColor.bind(this); this.getSizeStyles = this.getSizeStyles.bind(this); this.getEdgeSizeStyles = this.getEdgeSizeStyles.bind(this); this.renderLoadingIndicator = this.renderLoadingIndicator.bind(this); } getBackgroundColor() { return ({ backgroundColor: this.props.backgroundColor, }); } getEdgeColor() { return ({ borderColor: this.props.color, }); } getSizeStyles() { return ({ height: this.props.height, width: this.props.width, }); } getEdgeSizeStyles() { return ({ height: this.props.borderLength, width: this.props.borderLength, }); } renderLoadingIndicator() { if (!this.props.isLoading) { return null; } return (); }render() { return ( ); }}Viewfinder.propTypes = { backgroundColor: PropTypes.string, borderWidth: PropTypes.number, borderLength: PropTypes.number, color: PropTypes.string, height: PropTypes.number, isLoading: PropTypes.bool, width: PropTypes.number,};Viewfinder.defaultProps = { backgroundColor: 'transparent', borderWidth: 3, borderLength: 20, color: COLOR_MAIN, height: 220, isLoading: false, width: 220,};module.exports = Viewfinder; {this.renderLoadingIndicator()}
大功告成~最后上张效果图:
首先打开终端,在相应的目录下输入命令创建新项目
react-native init CameraDemo
项目创建完成,进入项目根目录下输入命令下载react-native-camera库
1.npm install react-native-camera@https://github.com/lwansbrough/react-native-camera.git --save2.react-native link react-native-camera
1.打开android/app/src/main/java/[...]/MainApplication.java文件,添加import com.lwansbrough.RCTCamera.RCTCameraPackage;
,在getPackages()方法里添加new RCTCameraPackage(),
2.打开android/settings.gradle文件,添加
include ':react-native-camera'project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
3.打开android/app/build.gradle文件,在dependencies{}中添加compile project(':react-native-camera'
4.在AndroidManifest.xml配置文件中添加相关权限:
//相机权限 //震动权限
注:android配置的前三个步骤一般情况下会自动添加,若没有添加,按上述步骤手动添加!
1.使用Xcode打开CameraDemo/ios/CameraDemo.xcodeproj文件,在Project navigator->Libraries文件夹上右击选择Add Files to 'CameraDemo';
2.选择项目中的node_modules->react-native-camera并且添加RCTCamera.xcodeproj文件;
3.在Build Phases中添加libRCTCamera.a;
4.在Build Settings中找到Search Paths下的Header Search Paths,添加$(SRCROOT)/../../react-native/React和$(SRCROOT)/../../../React,并且选择recursive;
如下图:
5.打开ScanDemo/ios/ScanDemo/Info.plist文件,添加下列权限
NSCameraUsageDescription 请允许使用您的相机 NSLocationWhenInUseUsageDescription NSPhotoLibraryUsageDescription 请允许打开您的相册
注:ios中前三个步骤也会自动加载,若没有添加,需按上述步骤手动添加!
1.scan.js代码
import React, { Component } from 'react';import { connect } from 'react-redux';import { View, Text, StyleSheet, Image, Platform, Vibration, TouchableOpacity, Animated, Easing, Dimensions} from 'react-native';const {width, height} = Dimensions.get('window');import {ToastMessage} from '../../utils/toast';import Camera from 'react-native-camera';import ViewFinder from '../../components/order/viewFinder';import backIcon from '../../../assets/img/backIcon.png';//返回按钮import scanLine from '../../../assets/img/scan_line.png';//扫描线export default class Scan extends Component { constructor(props) { super(props); this.camera = null; this.state = { transCode:'',//条码 openFlash: false, active: true, flag:true, fadeInOpacity: new Animated.Value(0), // 初始值 isEndAnimation:false,//结束动画标记 } this._goBack = this._goBack.bind(this); this._startAnimation = this._startAnimation.bind(this); this.barcodeReceived = this.barcodeReceived.bind(this); this._search = this._search.bind(this); this._changeFlash = this._changeFlash.bind(this); this.changeState = this.changeState.bind(this); } componentDidMount() { this._startAnimation(false); } //开始动画,循环播放 _startAnimation(isEnd) { Animated.timing(this.state.fadeInOpacity, { toValue: 1, duration: 3000, easing: Easing.linear }).start( () => { if (isEnd){ this.setState({ isEndAnimation:true }) return; } if (!this.state.isEndAnimation){ this.state.fadeInOpacity.setValue(0); this._startAnimation(false) } } ); console.log("开始动画"); } barcodeReceived(e) { if (e.data !== this.transCode) { Vibration.vibrate([0, 500, 200, 500]); this.transCode = e.data; // 放在this上,防止触发多次,setstate有延时 if(this.state.flag){ this.changeState(false); //通过条码编号获取数据 } console.log("transCode="+this.transCode); } } //返回按钮点击事件 _goBack() { this.setState({ isEndAnimation:true, }); this.props.navigator.pop(); } //开灯关灯 _changeFlash() { this.setState({ openFlash: !this.state.openFlash, }); } //改变请求状态 changeState(status){ this.setState({ flag:status }); console.log('status='+status); } render(){ const { openFlash, active, } = this.state; return({(() => { if (active) { return ( ) }}const styles =StyleSheet.create({ allContainer:{ flex:1, }, container: { ...Platform.select({ ios: { height: 64, }, android: { height: 50 } }), backgroundColor:BLACK_COLOR, opacity:0.5 }, titleContainer: { flex: 1, ...Platform.select({ ios: { paddingTop: 15, }, android: { paddingTop: 0, } }), flexDirection: 'row', }, leftContainer: { flex:0, justifyContent: 'center', }, backImg: { marginLeft: 10, }, cameraStyle: { alignSelf: 'center', width: width, height: height, }, flash: { flexDirection: 'column', alignItems: 'center', justifyContent: 'flex-start', marginTop: 60, }, flashIcon: { fontSize: 1, color: WHITE_COLOR, }, text: { fontSize: 14, color: WHITE_COLOR, marginTop:5 }, icon:{ color:WHITE_COLOR, fontSize:20, fontFamily:'iconfont' }, scanLine:{ alignSelf:'center', }, centerContainer:{ ...Platform.select({ ios: { height: 80, }, android: { height: 60, } }), width:width, backgroundColor:BLACK_COLOR, opacity:0.5 }, bottomContainer:{ alignItems:'center', backgroundColor:BLACK_COLOR, alignSelf:'center', opacity:0.5, flex:1, width:width }, fillView:{ width:(width-220)/2, height:220, backgroundColor:BLACK_COLOR, opacity:0.5 }, scan:{ width:220, height:220, alignSelf:'center' }})this.camera = cam} style={styles.cameraStyle} barcodeScannerEnabled={true} onBarCodeRead={ this.barcodeReceived } torchMode={openFlash ? 'on' : 'off'}> ); } })()}将运单上的条码放入框内即可自动扫描。 开灯/关灯
2.viewFinder.js代码
import React, { Component, PropTypes,} from 'react';import { ActivityIndicator, StyleSheet, View,} from 'react-native';const styles = StyleSheet.create({ container: { alignItems: 'center', justifyContent: 'center', position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, }, viewfinder: { alignItems: 'center', justifyContent: 'center', backgroundColor: 'transparent', }, topLeftEdge: { position: 'absolute', top: 0, left: 0, }, topRightEdge: { position: 'absolute', top: 0, right: 0, }, bottomLeftEdge: { position: 'absolute', bottom: 0, left: 0, }, bottomRightEdge: { position: 'absolute', bottom: 0, right: 0, },});class Viewfinder extends Component { constructor(props) { super(props); this.getBackgroundColor = this.getBackgroundColor.bind(this); this.getSizeStyles = this.getSizeStyles.bind(this); this.getEdgeSizeStyles = this.getEdgeSizeStyles.bind(this); this.renderLoadingIndicator = this.renderLoadingIndicator.bind(this); } getBackgroundColor() { return ({ backgroundColor: this.props.backgroundColor, }); } getEdgeColor() { return ({ borderColor: this.props.color, }); } getSizeStyles() { return ({ height: this.props.height, width: this.props.width, }); } getEdgeSizeStyles() { return ({ height: this.props.borderLength, width: this.props.borderLength, }); } renderLoadingIndicator() { if (!this.props.isLoading) { return null; } return (); }render() { return ( ); }}Viewfinder.propTypes = { backgroundColor: PropTypes.string, borderWidth: PropTypes.number, borderLength: PropTypes.number, color: PropTypes.string, height: PropTypes.number, isLoading: PropTypes.bool, width: PropTypes.number,};Viewfinder.defaultProps = { backgroundColor: 'transparent', borderWidth: 3, borderLength: 20, color: COLOR_MAIN, height: 220, isLoading: false, width: 220,};module.exports = Viewfinder; {this.renderLoadingIndicator()}
大功告成~最后上张效果图:
转载地址:http://qwrni.baihongyu.com/