从网上看了很多关于react native实现条码扫描的文章,里面出现了很多第三方库,有的文章说react-native-camera不能支持Android,我就自己试着写写,发现他可以兼容ios和Android。下面就来看看怎么实现吧~

一、新建项目

首先打开终端,在相应的目录下输入命令创建新项目

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配置文件中添加相关权限:

//相机权限

//震动权限

注: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;

如下图:

2cef1baf9a6f

QQ20170419-140900@2x.png

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 (

ref={cam => this.camera = cam}

style={styles.cameraStyle}

barcodeScannerEnabled={true}

onBarCodeRead={

this.barcodeReceived

}

torchMode={openFlash ? 'on' : 'off'}>

opacity: 1,

transform:[{

translateY:this.state.fadeInOpacity.interpolate({

inputRange:[0,1],

outputRange:[0,220]

})

}]

}]}>

style={[

styles.text,

{

textAlign: 'center',

width: 220,

marginTop: active ? 25 : 245,

},

]}

numberOfLines={2}

>

将运单上的条码放入框内即可自动扫描。

开灯/关灯

);

}

})()}

)

}

}

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 (

animating={this.props.isLoading}

color={this.props.color}

size="large"

/>

);

}

render() {

return (

style={[

this.getEdgeColor(),

this.getEdgeSizeStyles(),

styles.topLeftEdge,

{

borderLeftWidth: this.props.borderWidth,

borderTopWidth: this.props.borderWidth,

},

]}

/>

style={[

this.getEdgeColor(),

this.getEdgeSizeStyles(),

styles.topRightEdge,

{

borderRightWidth: this.props.borderWidth,

borderTopWidth: this.props.borderWidth,

},

]}

/>

{this.renderLoadingIndicator()}

style={[

this.getEdgeColor(),

this.getEdgeSizeStyles(),

styles.bottomLeftEdge,

{

borderLeftWidth: this.props.borderWidth,

borderBottomWidth: this.props.borderWidth,

},

]}

/>

style={[

this.getEdgeColor(),

this.getEdgeSizeStyles(),

styles.bottomRightEdge,

{

borderRightWidth: this.props.borderWidth,

borderBottomWidth: this.props.borderWidth,

},

]}

/>

);

}

}

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;

大功告成~最后上张效果图:

2cef1baf9a6f

1866D1330B2C6E2F40A40A7E7246C6BD.jpg

最近很多简友问我资源在哪下载,我就把代码整理了一下,发到了github上,现附上地址CameraDemo,以便大家下载~

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐