react-native中基于react-native-camera的扫一扫功能
效果示例图

示例代码
/* eslint-disable react-native/no-inline-styles */
import React, {
createRef,
forwardRef,
useEffect,
useImperativeHandle,
useRef,
useState,
} from 'react';
import {
StyleSheet,
View,
Modal,
Image,
TouchableOpacity,
Text,
ImageBackground,
Animated,
NativeModules,
Platform,
StatusBar,
} from 'react-native';
import { RNCamera } from 'react-native-camera';
import { pxToPd, pxToPdT } from '../../common/js/device';
const { StatusBarManager } = NativeModules;
// 状态栏高度
const StatusBarHeight = Platform.select({
ios: StatusBarManager.HEIGHT,
android: StatusBar.currentHeight,
});
const ScanQRCodeComponent = forwardRef((props, ref) => {
const animation = useRef(new Animated.Value(0)).current;
const [visible, setVisible] = useState(false);
const [options, setOptions] = useState({
success: null,
});
const hide = (type, value = '') => {
setVisible(false);
options.success({
type: type,
data: value,
});
};
const show = params => {
setOptions({
...options,
success: params.success,
});
setVisible(true);
};
//点击关闭
const closeCameraHandle = () => {
console.log('[关闭]');
hide('close', null);
};
const handleBarcodeScanned = ({ data }) => {
hide('submit', data);
};
const translateY = animation.interpolate({
inputRange: [0, 1],
outputRange: [20, 170], // Instead of percentages, use actual pixel values.
});
useImperativeHandle(ref, () => ({
show,
}));
useEffect(() => {
Animated.loop(
Animated.sequence([
Animated.timing(animation, {
toValue: 1,
duration: 1500,
useNativeDriver: true,
}),
Animated.timing(animation, {
toValue: 0,
duration: 1500,
useNativeDriver: true,
}),
]),
).start();
}, [visible]);
return (
<>
<Modal visible={visible} animationType="fade" transparent>
<View style={styles.cameraWrap}>
<View style={styles.cameraBlock}>
{/* 自定义头部 */}
<View style={{ width: '100%', backgroundColor: '#000' }}>
<View style={{ width: '100%', height: StatusBarHeight }} />
<View style={{ width: '100%' }}>
<View
style={{
width: '93.6%',
height: pxToPd(70),
marginLeft: '3.2%',
flexDirection: 'row',
}}>
<View style={{ width: '25%', position: 'relative' }}>
<TouchableOpacity onPress={closeCameraHandle}>
<Image
style={{
width: pxToPd(38),
height: pxToPd(38),
position: 'absolute',
left: pxToPd(0),
top: pxToPd(16),
}}
source={require('../../common/images/back_white.png')}
/>
</TouchableOpacity>
</View>
<View style={{ width: '50%' }}>
<Text
style={{
lineHeight: pxToPd(70),
textAlign: 'center',
fontSize: pxToPdT(36),
color: '#fff',
fontWeight: 'bold',
}}>
扫一扫
</Text>
</View>
<View
style={{
width: '25%',
alignItems: 'flex-end',
justifyContent: 'center',
}}
/>
</View>
</View>
</View>
{/* 摄像机 */}
<RNCamera
style={styles.camera}
onBarCodeRead={handleBarcodeScanned}
captureAudio={false}
/>
{/* 相框 */}
<View style={styles.scanBox}>
<ImageBackground
style={styles.scanBoxBg}
source={require('../../common/images/scan_box.png')}>
<View style={styles.scanBlock}>
<Animated.View
style={[styles.scanLine, { transform: [{ translateY }] }]}
/>
</View>
</ImageBackground>
</View>
</View>
</View>
</Modal>
</>
);
});
const styles = StyleSheet.create({
cameraWrap: {
flex: 1,
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
zIndex: 9999,
backgroundColor: 'rgba(0,0,0,0.6)',
},
cameraBlock: {
flex: 1,
position: 'relative',
},
closeCamera: {
borderRadius: pxToPd(30),
width: pxToPd(80),
height: pxToPd(80),
position: 'absolute',
top: '10%',
left: '3.2%',
zIndex: 99,
},
camera: {
width: '100%',
height: '100%',
},
// 相框
scanBox: {
width: 200,
height: 200,
position: 'absolute',
top: '50%',
left: '50%',
marginTop: -100,
marginLeft: -100,
},
scanBoxBg: {
width: '100%',
height: '100%',
},
scanBlock: {
width: '100%',
height: '100%',
position: 'relative',
overflow: 'hidden',
},
scanLine: {
position: 'absolute',
height: pxToPd(24),
width: '80%',
left: '10%',
backgroundColor: '#fff',
borderRadius: pxToPd(6),
},
});
export const scanCodeRef = createRef();
export default ScanQRCodeComponent;
页面中引入组件使用
<ScanQRCodeComponent ref={scanCodeRef} />
scanCodeRef.current?.show({
success: res => {
console.log('{]', res);
if (res.type === 'submit') {
let code = res.data;
if (code && code !== 'NaN') {
console.log(code);
} else {
showToastRef.current.show({
type: 'fail', //类型:success:成功;fail:失败
title: '请正确扫码',
content: '',
success: () => {},
});
}
}
},
});
版本
"react": "18.2.0",
"react-native": "0.72.3",
"react-native-camera": "^4.2.1",