19

How to add a mask on top of the react-native-camera?

I'm building the UI for a React Native QRCode scanner app using react-native-camera.

The overlay mask on top of the camera should be in light grey color, but the middle part must keep transparent (see-through).

But when I change the backgroundColor on my outer mask, it seems also affect the center part. I mean, of course, it is behind its child view.

The code down below is a simplified version of the snapshot.

<Camera
  ref={cam => {
    this.camera = cam;
  }}
  onBarCodeRead={this._onBarCodeRead}
  style={styles.cameraView}
  aspect={Camera.constants.Aspect.fill}
  playSoundOnCapture
>
  <View
    style={{
      position: 'absolute',
      top: 0,
      left: 0,
      width: '100%',
      height: '100%',
      backgroundColor: 'rgba(0.2, 0.2, 0.2, 0.2)',
      alignItems: 'center',
      justifyContent: 'space-around',
    }}
  >
    <View
      style={{
        width: 300,
        height: 300,
        backgroundColor: 'transparent',
        borderColor: 'white',
        borderWidth: 1,
      }}
    />
  </View>
</Camera>

The basic idea is here

Any idea how to get this done?

Chisko
  • 3,092
  • 6
  • 27
  • 45
FisNaN
  • 2,517
  • 2
  • 24
  • 39

3 Answers3

33

I finally figure out this one. The idea is to create 3 rows like a burger and then calculate the height and width at runtime.

The center row has 3 view components, the middle one has a transparent background and white border.

(the value, 300, comes from the size of the center view (transparent area), I divided it by 10 to compute a smaller ratio for flexboxes)

Barcode mask demo

export default class CameraScreen extends React.Component<any, any> {
  render() {
    const { height, width } = Dimensions.get('window');
    const maskRowHeight = Math.round((AppStore.height - 300) / 20);
    const maskColWidth = (width - 300) / 2;

    return (
      <View style={styles.container}>
        <Camera
          ref={cam => {
            this.camera = cam;
          }}
          onBarCodeRead={this._onBarCodeRead}
          style={styles.cameraView}
          aspect={Camera.constants.Aspect.fill}
          playSoundOnCapture
        >
          <View style={styles.maskOutter}>
            <View style={[{ flex: maskRowHeight  }, styles.maskRow, styles.maskFrame]} />
             <View style={[{ flex: 30 }, styles.maskCenter]}>
             <View style={[{ width: maskColWidth }, styles.maskFrame]} />
             <View style={styles.maskInner} />
            <View style={[{ width: maskColWidth }, styles.maskFrame]} />
          </View>
        <View style={[{ flex: maskRowHeight }, styles.maskRow, styles.maskFrame]} />
      </View>
        </Camera>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  cameraView: {
    flex: 1,
    justifyContent: 'flex-start',
  },
  maskOutter: {
    position: 'absolute',
    top: 0,
    left: 0,
    width: '100%',
    height: '100%',
    alignItems: 'center',
    justifyContent: 'space-around',
  },
  maskInner: {
    width: 300,
    backgroundColor: 'transparent',
    borderColor: 'white',
    borderWidth: 1,
  },
  maskFrame: {
    backgroundColor: 'rgba(1,1,1,0.6)',
  },
  maskRow: {
    width: '100%',
  },
  maskCenter: { flexDirection: 'row' },
});

Update: The height ratio changes between the different brand phones depend on it uses physical/soft buttons. I replaced the fixed height with flex instead.

FisNaN
  • 2,517
  • 2
  • 24
  • 39
  • The height and width in render function are just for demo purpose. These should be done inside `consturctor` – FisNaN Feb 01 '18 at 21:02
  • @random1234 Yes, the square shape just a reference point for users. I also tried another QC code scanner packages (which often a wrapper of `react-native-camera`), they all scan the full image due to the native code behind it. So if there is multiple QC codes in your frame. It will have some trouble to scan the correct one. – FisNaN Apr 18 '18 at 21:17
  • So there is no way to make it scan only a part of the cameras view? – random1234 Apr 19 '18 at 05:32
  • @random1234 I didn't manage to do that. However from user perspective, they won't notice at all. – FisNaN Apr 19 '18 at 20:52
  • 1
    They do if the QR-codes are near and above each other =( – random1234 Apr 20 '18 at 06:43
  • how to change value of height and width? – Chanrithisak Phok Jun 24 '22 at 04:23
4

You can use this:
react-native-barcode-mask

Hugo L.F.
  • 61
  • 4
  • react-native-barcode-mask uses react-native-camera which is depreciated. It's a shame it's not been updated to use the more popular react-native-vision-camera – Gavin Coates Feb 21 '23 at 13:58
0

You need to use some masked native views (iOs, Android) and wrap your content in it

Or you can use our small lib for this https://github.com/ibitcy/react-native-hole-view