react-native打开摄像机、ios端二维码扫描

近日很多人反映react-native-camera怎么用?还有人说ios的二维码扫描咋没有呢?其实这些问题在react-native-camera上都有介绍,在ideacreation/React-native-barcodescanner中也有讲,如果是ios的话请使用react-native-camera;下面我就RN调用摄像机做下简单的介绍吧:


一、首先打开终端命令,进入项目,输入一下命令:

npm install react-native-camera@https://github.com/lwansbrough/react-native-camera.git --save

等待安装完成后,然后输入:react-native link react-native-camera

这是在你的工程中就有了这个组件。

二、建立项目(这里面的代码和图片基本上都是作者的代码,我只是稍微修改了下)

2.1、首先再项目下面新建一个assets,把需要的图片拷贝进去

2.2、下面新建一个js文件,放置摄像机的界面,我这里就用入口文件介绍:

文件的内容如下:

import React, { Component } from 'react';
import {
  AppRegistry,
  Image,
  StatusBar,
  StyleSheet,
  TouchableOpacity,
  View,
} from 'react-native';
import Camera from 'react-native-camera';


export default class First extends Component {
  constructor(props) {
    super(props);

    this.camera = null;

    this.state = {
      camera: {
        aspect: Camera.constants.Aspect.fill,
        captureTarget: Camera.constants.CaptureTarget.cameraRoll,
        type: Camera.constants.Type.back,
        orientation: Camera.constants.Orientation.auto,
        flashMode: Camera.constants.FlashMode.auto,
      },
      isRecording: false
    };

    this.takePicture = this.takePicture.bind(this);
    this.startRecording = this.startRecording.bind(this);
    this.stopRecording = this.stopRecording.bind(this);
    this.switchType = this.switchType.bind(this);
    this.switchFlash = this.switchFlash.bind(this);
  }

  takePicture() {
    if (this.camera) {
      this.camera.capture()
        .then((data) => console.log(data))
        .catch(err => console.error(err));
    }
  }

  startRecording() {
    if (this.camera) {
      this.camera.capture({mode: Camera.constants.CaptureMode.video})
          .then((data) => console.log(data))
          .catch(err => console.error(err));
      this.setState({
        isRecording: true
      });
    }
  }

  stopRecording() {
    if (this.camera) {
      this.camera.stopCapture();
      this.setState({
        isRecording: false
      });
    }
  }

  switchType() {
    let newType;
    const { back, front } = Camera.constants.Type;

    if (this.state.camera.type === back) {
      newType = front;
    } else if (this.state.camera.type === front) {
      newType = back;
    }

    this.setState({
      camera: {
        ...this.state.camera,
        type: newType,
      },
    });
  }

  get typeIcon() {
    let icon;
    const { back, front } = Camera.constants.Type;

    if (this.state.camera.type === back) {
      icon = require('./assets/ic_camera_rear_white.png');
    } else if (this.state.camera.type === front) {
      icon = require('./assets/ic_camera_front_white.png');
    }

    return icon;
  }

  switchFlash() {
    let newFlashMode;
    const { auto, on, off } = Camera.constants.FlashMode;

    if (this.state.camera.flashMode === auto) {
      newFlashMode = on;
    } else if (this.state.camera.flashMode === on) {
      newFlashMode = off;
    } else if (this.state.camera.flashMode === off) {
      newFlashMode = auto;
    }

    this.setState({
      camera: {
        ...this.state.camera,
        flashMode: newFlashMode,
      },
    });
  }

  get flashIcon() {
    let icon;
    const { auto, on, off } = Camera.constants.FlashMode;

    if (this.state.camera.flashMode === auto) {
      icon = require('./assets/ic_flash_auto_white.png');
    } else if (this.state.camera.flashMode === on) {
      icon = require('./assets/ic_flash_on_white.png');
    } else if (this.state.camera.flashMode === off) {
      icon = require('./assets/ic_flash_off_white.png');
    }

    return icon;
  }

  render() {
    return (
      <View style={styles.container}>
        <StatusBar
          animated
          hidden
        />
        <Camera
          ref={(cam) => {
            this.camera = cam;
          }}
          style={styles.preview}
          aspect={this.state.camera.aspect}
          captureTarget={this.state.camera.captureTarget}
          type={this.state.camera.type}
          flashMode={this.state.camera.flashMode}
          defaultTouchToFocus
          mirrorImage={false}
        />
        <View style={[styles.overlay, styles.topOverlay]}>
          <TouchableOpacity
            style={styles.typeButton}
            onPress={this.switchType}
          >
            <Image
              source={this.typeIcon}
            />
          </TouchableOpacity>
          <TouchableOpacity
            style={styles.flashButton}
            onPress={this.switchFlash}
          >
            <Image
              source={this.flashIcon}
            />
          </TouchableOpacity>
        </View>
        <View style={[styles.overlay, styles.bottomOverlay]}>
          {
            !this.state.isRecording
            &&
            <TouchableOpacity
                style={styles.captureButton}
                onPress={this.takePicture}
            >
              <Image
                  source={require('./assets/ic_photo_camera_36pt.png')}
              />
            </TouchableOpacity>
            ||
            null
          }
          <View style={styles.buttonsSpace} />
          {
              !this.state.isRecording
              &&
              <TouchableOpacity
                  style={styles.captureButton}
                  onPress={this.startRecording}
              >
                <Image
                    source={require('./assets/ic_videocam_36pt.png')}
                />
              </TouchableOpacity>
              ||
              <TouchableOpacity
                  style={styles.captureButton}
                  onPress={this.stopRecording}
              >
                <Image
                    source={require('./assets/ic_stop_36pt.png')}
                />
              </TouchableOpacity>
          }
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  preview: {
    flex: 1,
    justifyContent: 'flex-end',
    alignItems: 'center',
  },
  overlay: {
    position: 'absolute',
    padding: 16,
    right: 0,
    left: 0,
    alignItems: 'center',
  },
  topOverlay: {
    top: 0,
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
  bottomOverlay: {
    bottom: 0,
    backgroundColor: 'rgba(0,0,0,0.4)',
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
  },
  captureButton: {
    padding: 15,
    backgroundColor: 'white',
    borderRadius: 40,
  },
  typeButton: {
    padding: 5,
  },
  flashButton: {
    padding: 5,
  },
  buttonsSpace: {
    width: 10,
  },
});

AppRegistry.registerComponent('First', () => First);</span></span>


大家注意:现在的RN版本做了下调整,入口文件index.android.js和index.ios.js都作为导出文件,也就是在class前面加了export default,最下面的注册入口没改,这个class是导出给---项目名下面有个_tests_的文件中,里面也有两个js文件,在这个里面导入的,和原来的写法稍微不同;


2.3、然后编译:android和ios都挂了,头大了,

android我是7.0的模拟器,直接闪退了,ios打不开,白屏然后过一会也闪退了;

然后我换了个红米真机用下,可以打开摄像机,我又换了6.0、5.0、4.4的模拟器都可以打开摄像机,就是7.0坑爹的打不开,估计是不兼容吧,希望改进了,这里我还没有研究为啥7.0打不开闪退的问题:

2.3.1、ios我用xcode打开项目-->ios-->First.xcodeproj,然后编译一看,有5个感叹号!

libRCTCamera.a(CameraFocusSquare.o)) was built for newer iOS version (8.2) than being linked (8.0)



也就是说camera最低的编译版本是8.2,我的版本是8.0,需要调整我的xcode编译版本,具体的操作步骤如下:

点击项目名(first)--->然后选择右边的选项卡 General ---> Deployment Info --->Deployment Target,调整成8.2以上的版本,我这次改成了10.0的;然后编译,不报感叹号了,但是报错了;


2.3.2、报错内容如下:

The app’s Info.plist must contain an NSPhotoLibraryUsageDescription key with a string value explaining to the user how the app uses this data.

这是因为没有加权限的原因,在info里面机上摄像机的权限就行了,plist里面必须加上NSPhotoLibraryUsageDescription和NSCameraUsageDescription的键值对才行:

具体查看 http://blog.csdn.net/zp511253886/article/details/52584210,

然后编译,真高兴啊,通过了,然后在ios模拟器上点击确定打开摄像机,就可以了,但是由于模拟器不支持摄像机,所以看不到东西哦!


2.4、下面来分析下上面的代码:

2.4.1、首先导入camera:

import Camera from 'react-native-camera';

2.4.2、接着状态机里面的几个状态如下:

     camera: {
        aspect: Camera.constants.Aspect.fill,
        captureTarget: Camera.constants.CaptureTarget.cameraRoll,
        type: Camera.constants.Type.back,
        orientation: Camera.constants.Orientation.auto,
        flashMode: Camera.constants.FlashMode.auto,
      },
      isRecording: false</span></span>

其中aspect是指图像和屏幕的拉伸宽度,有三个参数,一个是默认的fill,一个是fit,一个是stretch,具体他们的对比如下图:



captureTarget是指相片存储的位置,ios默认是cameraRoll,android默认是disk,作者提供了4中方式,但是最后一个存储在内存中已经被废弃了:
而且作者建议用disk:

Camera.constants.CaptureTarget.cameraRoll (ios only default), Camera.constants.CaptureTarget.disk(android default), Camera.constants.CaptureTarget.tempCamera.constants.CaptureTarget.memory (deprecated)


type指的是前置还是后置摄像头;

orientation指的是摄像机横屏还是竖屏,默认是随着屏幕自动调整的;
还有一个flashMode是闪关灯的模式,默认是自动的;
当然官方文档中还有
图片的captureQuality(有4种模式:heigh、medium、low、photo)
还有焦点改变的事件:onFocusChanged,简单的理解就是我们手指点击图像的哪个地方就聚焦哪个地方;
大小改变的事件也就是onZoomChanged,表示景物离我们远近的事件;
mirrorImage如果值为true的话,表示图像变成镜像的了;
还有ios的二维码识别:onBarCodeRead;
等等其他的事件,需要的话请参考官方文档;



2.2.2、然后进行布局,我的界面上主要有4个按键,一个是左上角的前后摄像头的切换,右上角的闪关灯的开关,底部的拍照和录像的按钮;

2.2.2.1、左上角的是switchType()这个方法,初始状态机里面的是后置摄像机,这里我用的是模拟器,所以调成了前置摄像机,

2.2.2.2、紧接着是get typeIcon()这个方法是改变前后摄像机的图标的

2.2.2.3、其中takePicture是拍照的方法,startRecording和stopRecording是开始录像和停止录像的方法,takePicture和startRecording调用的是camera的capture方法:

capture的参数可以是

  • audio (具体需要查看captureAudio)

  • mode (具体需要查看captureMode,这里面有两个值一个是默认的fill代表的是图片,一个是video代表的是视频)

  • target (具体需要查看captureTarget)

  • metadata 这个加到图片中的元数据

    • location 这是从navigator.geolocation.getCurrentPosition()返回的值 (React Native's geolocation polyfill).意思呢就是把gps的坐标信息加到图片中

  • rotation 这个呢是把图片旋转多少度。


stopRecording调用的是摄像机的stopCapture方法;

switchFlash和flashIcon分别是改变闪关灯的开关和闪关灯的图标的;

三、介绍下ios二维码的识别:


<Camera
          ref={(cam) => {
            this.camera = cam;
          }}
          style={styles.preview}
          aspect={this.state.camera.aspect}
          captureTarget={this.state.camera.captureTarget}
          type={this.state.camera.type}
          flashMode={this.state.camera.flashMode}
          defaultTouchToFocus
          mirrorImage={false}
        />
onBarCodeRead=(e)=>{
  console.log(e.data);
}

意思呢就是说当识别出来二维码后,传回的是一个参数,这个参数里面就包含有二维码的数据data


​完整代码在 https://github.com/LiuC520/react-native-lc-opencamera/中,请下载自行运行下看下哦

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值