react-native 实现条码扫描(ios&android)
2017-04-19 16:23
621 查看
从网上看了很多关于react native实现条码扫描的文章,里面出现了很多第三方库,有的文章说react-native-camera不能支持Android,我就自己试着写写,发现他可以兼容ios和Android。下面就来看看怎么实现吧~http://www.jianshu.com/p/2cef1baf9a6f
首先打开终端,在相应的目录下输入命令创建新项目
项目创建完成,进入项目根目录下输入命令下载react-native-camera库
1.打开android/app/src/main/java/[...]/MainApplication.java文件,添加
2.打开android/settings.gradle文件,添加
3.打开android/app/build.gradle文件,在dependencies{}中添加
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;
如下图:
![](http://upload-images.jianshu.io/upload_images/5357992-4c5f6bb88d28e4ea.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
QQ20170419-140900@2x.png
5.打开ScanDemo/ios/ScanDemo/Info.plist文件,添加下列权限
注:ios中前三个步骤也会自动加载,若没有添加,需按上述步骤手动添加!
1.scan.js代码
2.viewFinder.js代码
大功告成~最后上张效果图:
![](http://upload-images.jianshu.io/upload_images/5357992-b739d3b2c687d6a4.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
1866D1330B2C6E2F40A40A7E7246C6BD.jpg
一、新建项目
首先打开终端,在相应的目录下输入命令创建新项目react-native init CameraDemo
项目创建完成,进入项目根目录下输入命令下载react-native-camera库
1.npm install react-native-camera@https://github.com/lwansbrough/react-native-camera.git --save 2.react-native link react-native-camera
二、Android配置
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配置文件中添加相关权限:
<uses-permission android:name="android.permission.CAMERA" />//相机权限 <uses-permission android:name="android.permission.VIBRATE" />//震动权限 <uses-feature android:name="android.hardware.camera" android:required="false" /> <uses-feature android:name="android.hardware.camera.front" android:required="false" />
注:android配置的前三个步骤一般情况下会自动添加,若没有添加,按上述步骤手动添加!
三、iOS配置
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;
如下图:
![](http://upload-images.jianshu.io/upload_images/5357992-4c5f6bb88d28e4ea.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
QQ20170419-140900@2x.png
5.打开ScanDemo/ios/ScanDemo/Info.plist文件,添加下列权限
<key>NSCameraUsageDescription</key> <string>请允许使用您的相机</string> <key>NSLocationWhenInUseUsageDescription</key> <string></string> <key>NSPhotoLibraryUsageDescription</key> <string>请允许打开您的相册</string>
注: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( <View style={styles.allContainer}> {(() => { if (active) { return ( <Camera ref={cam => this.camera = cam} style={styles.cameraStyle} barcodeScannerEnabled={true} onBarCodeRead={ this.barcodeReceived } torchMode={openFlash ? 'on' : 'off'}> <View style={styles.container}> <View style={styles.titleContainer}> <View style={styles.leftContainer}> <TouchableOpacity activeOpacity={1} onPress={ this._goBack}> <View> <Image style={ styles.backImg } source={ backIcon }/> </View> </TouchableOpacity> </View> </View> </View> <View style={styles.centerContainer}/> <View style={{flexDirection:'row'}}> <View style={styles.fillView}/> <View style={styles.scan}> <ViewFinder/> <Animated.View style={[styles.scanLine, { opacity: 1, transform:[{ translateY:this.state.fadeInOpacity.interpolate({ inputRange:[0,1], outputRange:[0,260] }) }] }]}> <Image source={scanLine}/> </Animated.View> </View> <View style={styles.fillView}/> </View> <View style={styles.bottomContainer}> <Text style={[ styles.text, { textAlign: 'center', width: 260, marginTop: active ? 25 : 285, }, ]} numberOfLines={2} > 将运单上的条码放入框内即可自动扫描。 </Text> <TouchableOpacity onPress={this._changeFlash}> <View style={styles.flash}> <Text style={styles.icon}></Text> <Text style={styles.text}> 开灯/关灯 </Text> </View> </TouchableOpacity> </View> </Camera> ); } })()} </View> ) } } 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' } })
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 ( <ActivityIndicator animating={this.props.isLoading} color={this.props.color} size="large" /> ); } render() { return ( <View style={[styles.container, this.getBackgroundColor()]}> <View style={[styles.viewfinder, this.getSizeStyles()]}> <View style={[ this.getEdgeColor(), this.getEdgeSizeStyles(), styles.topLeftEdge, { borderLeftWidth: this.props.borderWidth, borderTopWidth: this.props.borderWidth, }, ]} /> <View style={[ this.getEdgeColor(), this.getEdgeSizeStyles(), styles.topRightEdge, { borderRightWidth: this.props.borderWidth, borderTopWidth: this.props.borderWidth, }, ]} /> {this.renderLoadingIndicator()} <View style={[ this.getEdgeColor(), this.getEdgeSizeStyles(), styles.bottomLeftEdge, { borderLeftWidth: this.props.borderWidth, borderBottomWidth: this.props.borderWidth, }, ]} /> <View style={[ this.getEdgeColor(), this.getEdgeSizeStyles(), styles.bottomRightEdge, { borderRightWidth: this.props.borderWidth, borderBottomWidth: this.props.borderWidth, }, ]} /> </View> </View> ); } } 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;
大功告成~最后上张效果图:
![](http://upload-images.jianshu.io/upload_images/5357992-b739d3b2c687d6a4.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
1866D1330B2C6E2F40A40A7E7246C6BD.jpg
相关文章推荐
- react-native 实现条码扫描(ios&android)
- 使用react-native-pull实现跨平台Android&IOS下拉刷新滑动回弹效果
- react-native 实现百度地图(ios&Android)
- 使用react-native-pull实现跨平台Android&IOS下拉刷新滑动回弹效果
- ReactNative Android和iOS的实现原理
- react-native-easy-toast, 一款简单易用的 Toast 组件,支持 Android&iOS.
- React-Native Android 与 IOS App使用一份代码实现方法
- 支持android&ios高度自适应及JS相互调用的组件react-native-webview2
- React-Native实现ListView组件之上拉刷新实例(iOS和Android通用)
- React-Native 开发 android & ios App,共享一份代码
- 《React-Native系列》23、 js实现下拉刷新效果(Android和iOS通用)
- react-native-easy-toast, 一款简单易用的 Toast 组件,支持 Android&iOS.
- react-native的兼容性(Android、Ios)
- React-Native 开发 android & ios App,共享一份代码
- 《React-Native系列》13、 组件封装之Dialog(iOS和Android通用)
- ReactNative中iOS和Android的style分开设置教程
- ReactNative js判断android还是ios
- React Native之ViewPagerAndroid仿淘宝首页顶部分类布局效果实现
- IOS、Android进阶之ReactNative热更新