原生模块、视图

如果React VR满足不了你的需求,你可以自定义的

有时在React VR没相关的组件,应用需要接入平台的API,也许你要复用已经存在的但在react中没有声明的js代码,如想写一些体验更好的代码、图片处理的多线程代码、数据库或者更高级的功能。

立方体例子

其中的一个用到原生模块的例子就是在React VR UI和从three.js添加到场景中的物体之间的交互,比如说在Three.js README里面的几何立方体。

设置场景

React VR框架能处理相机和渲染设置,你只需关注在场景中添加物体,关注物体的运动即可,首先在开始项目的一个文件 vr/client.jsinit函数中添加场景,并把场景做为VRInstance构造函数的一个参数,原生模块稍后再讲。

const scene = new  THREE.Scene();

const cubeModule = new  CubeModule();


const vr = new  VRInstance(bundle, 'CubeSample', parent, {

  cursorVisibility: 'visible',

  nativeModules: [ cubeModule ],

  scene: scene,

});

下一步我们创建立方体mesh并添加到场景中,这里依旧用three.js,我们修改几个地方让three.js物

体正确的出现在React VR中。

const cube = new  THREE.Mesh(

  new THREE.BoxGeometry(1, 1, 1),

  new THREE.MeshBasicMaterial(),

);

cube.position.z = -4;

scene.add(cube);

cubeModule.init(cube);

上面我们用cube对cubeModule进行初始化了,最后我们在cubeModule方法里面写帧更新的逻辑。

vr.render = function(timestamp) {

  const seconds = timestamp / 1000;

  cube.position.x = 0 + (1 * (Math.cos(seconds)));

  cube.position.y = 0.2 + (1 * Math.abs(Math.sin(seconds)));

};

使用原生模块

假设我想通过点击按钮改变立方体的颜色,就可以通过React Native桥,异步调用原生模块的changeCubeColor函数,上面的例子中在client.js中已经有了构造函数和init函数了,另外还有一个就是原生模块的。

export default class CubeModule extends Module {

  constructor() {

    super('CubeModule );

  }

  init(cube) {

    this.cube = cube;

  }

  changeCubeColor(color) {

    this.cube.material.color = new THREE.Color(color);

  }

};

然后我们在index.vr.jsonClick函数里调用changeCubeColor

import NativeModules from 'react-vr';

...

const CubeModule = NativeModules.CubeModule;

...

render() {

...

  <VrButton

    onClick={()=>CubeModule.changeCubeColor(hexColor)}

  ...

  </VrButton>

...

CubeSample中可以查看全部代码。

创建原生视图(View)

您可以空过实现原生视图控制在React VR代码中指定的属性如何与运行时代码交互。

你需要导入react-vr-web模块

import * as ReactVR from 'react-vr-web';

然后需要创建一个类继承RCTBaseView,在构造函数中需要创建OVRUI.UIView,然后在任何属性上注册getterssetters

你需要声明静态的describe函数,它在运行时决定哪个属性要从React vr代码中发送到运行时代码,这些是PropTypes的运行时实现。

class RCTTestLight extends ReactVR.RCTBaseView {

  constructor(guiSys: GuiSys) {

    super();

    const light = new THREE.AmbientLight();

    this.view = new OVRUI.UIView(guiSys);

    this.view.add(light);

    Object.defineProperty(

      this.props,

      'intensity',

      {

        set: value => {

          light.intensity = value;

        },

      }

    );

    this.props.intensity = 1;

  }

  static describe() {

    return merge(super.describe(), {

      // declare the native props sent from react to runtime

      NativeProps: {

        intensity: 'number',

      },

    });

  }

}

最后这个自定义的view必须要在react vr的上下文中注册,也就是在创建ReactVR.VRInstance时添加一个列表customViews

const vr = new ReactVR.VRInstance(bundlePath, appName, document.body, {

  customViews: [{name: 'TestLight', view: RCTTestLight}],

  ...options,

});

为了让TestLight组件在React VR代码中可用,需要用NativeMethodsMixin注册一个组件,propTypes也需要设置,以便让React VR内核来处理propTypes,viewConfig是用来支持Animated模块的,render需要返回一个用requireNativeComponent创建的组件。

const TestLight = React.createClass({

  mixins: [NativeMethodsMixin],

  propTypes: {

    ...View.propTypes,

    style: StyleSheetPropType(LayoutAndTransformPropTypes),

    intensity: PropTypes.number,

  },

  viewConfig: {

    uiViewClassName: 'AmbientLight',

    validAttributes: {

      ...ReactNativeViewAttributes.RCTView,

      intensity: true,

    },

  },

  getDefaultProps: function() {

    return {};

  };

  render: function() {

    return (

      <RKTestLight

        {...props}>

      </RKTestLight>

    );

  },

});

const RKTestLight = requireNativeComponent('TestLight', TestLight, {

nativeOnly: {},

});

module.exports = TestLight;