应用原生试图,在RN里是必不可少的一部分。如果有人在原生性能都做好了,间接拿来用或者微调一下试图局部就能够用也就不须要再另外造一个,一套轮子了。

步骤

官网文档十分具体了。间接援用如下:

1. 新建一个ViewManager子类2. 实现createViewInstance办法3. 通过注解@ReactProp或者@ReactPropGroup裸露视图的属性4. 在createViewManagers办法里注册这个manager5. 实现JS模块

和原生模块的开发根本一个流程。
然而,首先要有一个原生视图。是这样的:

public class FillingHoleView extends View {    // ...    public float getRadius()    public void setRadius(float radius)    public int getStrokeColor()    public void setStrokeColor(int color)    onDraw    onMeasure    // ...}

就是一个Android的视图,画一个圈。能够通过setter管制圈的色彩半径

而后就开始依照下面的程序开始增加代码。

ViewManager子类

public class FillingHoleViewManager extends SimpleViewManager<FillingHoleView> {    public static final String REACT_CLASS = "FillingHoleView";    ReactApplicationContext mCallerContext;    public FillingHoleViewManager(ReactApplicationContext reactContext) {        this.mCallerContext = reactContext;    }    @NonNull    @Override    public String getName() {        return REACT_CLASS;    }    @NonNull    @Override    protected FillingHoleView createViewInstance(@NonNull ThemedReactContext reactContext) {        return new FillingHoleView(reactContext);    }    @ReactProp(name = "radius", defaultFloat = 50f)    public void setRadius(FillingHoleView fillingHoleView, int radius) {        fillingHoleView.setRadius(radius);    }    @ReactProp(name = "color", defaultInt = 1)    public void setStrokeColor(FillingHoleView fillingHoleView, int color) {        fillingHoleView.setStrokeColor(Color.RED);    }}

应用SimpleViewManager有一个益处,它默认提供了背景色、透明度和Flex布局的性能,还有一些accessbility的性能。所以继承了这个view manager就能够应用flex布局了。

实现view manager的时候须要提供模块名称,在JS也是通过模块名称来获取原生模块的。

createViewInstance办法返回进去原生视图。

须要裸露给JS的属性通过@ReactProp或者@ReactGroupProp注解润饰。第一个参数是你的原生视图,第二个是要批改的属性。name是必须的。这些属性里只有值类型的能够提供具体的默认值,援用类型的只能是默认为null。

注册View Manager

如果还没有package类的话须要新建一个:

public class MyAppPackage implements ReactPackage {    @NonNull    @Override    public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {        List<NativeModule> modules = new ArrayList<>();        modules.add(new FillingEventHole(reactContext));        return modules;    }    @NonNull    @Override    public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {        return Arrays.<ViewManager>asList(            new FillingHoleViewManager(reactContext)        );    }

继承ReactPackage实现其中的办法。次要有两个,一个是注册原生模块的,一个是注册原生视图的。之后这个package还须要增加到你的application类里。参考这里。

在JS里应用你的原生视图

简略版本的能够参考官网:

// FillingHoleView.jsimport { requireNativeComponent } from 'react-native';/** * Composes `View`. * * - radius: number * - color: number * - width: number */module.exports = requireNativeComponent('FillingHoleView');

更加React的实现办法,能够参考这里:

import React from 'react';import { requireNativeComponent } from 'react-native';const FillingNativeView = requireNativeComponent('FillingHoleView');interface FillingHoleViewProps {  radius: number;  color: number; // 1, 2, 3  width?: number;}const FillingHoleView: React.FC<FillingHoleViewProps> = props => {  return <FillingNativeView {...props} />;};export { FillingHoleView };

requireNativeComponent返回的就是能够在其余React组件里应用的组件了。然而短少的是对于接管各种属性和办法的强制阐明。所以,在外满包一层(其实并没有减少理论的视图层级)能够在应用中主动提醒能够承受的属性等。

还有事件能够承受,这里能够参考官网。后续补充这部分内容。

布局

本文的例子是画一个背景色和半径可调的圈。

这里次要探讨的是绘图逻辑,通过setter制订半径,而后失去视图的宽高值(padding思考在内了)。这样,在视图中执行flex布局的时候会有一些奇怪的问题。

首先,React的单位和android的单位不是一回事。比方,本例中,在Android代码中设置宽度为50,在JS设置宽度为100在Android里拿到的是275(在不同分辨率下失去的值也是不一样的)。

所以在开发中,最好对立宽、高入口。比方在本文最好都从JS设置,而后从宽度里计算圆的半径。半径也能够在JS设置,然而在measure的时候宽度曾经失去了,半径还没有,或者是例子中的默认值。只有是Android这里拿到的值和JS失去的就是不同的(除非分辨率适合)。

下面说的是单位的问题。当初还要说宽度的问题。

宽度必须要有,否则这个原生视图在flex的布局零碎了是一个宽度、高度都是0的存在。如图:

绿色圆形就被当做宽、高都为0的存在了。具体代码:

<View style={styles.fillingNative}>  <FillingHoleView radius={50} color={2} />  <Text>2</Text></View>

fillingNative的款式为:

  fillingNative: {    flex: 1,    height: 160,    flexDirection: 'row',    justifyContent: 'flex-start',    alignItems: 'center',    backgroundColor: 'powderblue',  },

在这个状况下绿色圆曾经超出了边界,而且文字也间接显示在下面。反而看上面的黄色圆设置了宽度,只是呈现了下面说的单位不同的问题,布局失常。

红色圆球的问题在于设置宽度和发高度的形式和宽高度都必须明确给出的问题。能够看到红色圆和红色视图在纵向布局上有问题。当明确给出高度之后问题解决。如图:

设置宽高,除了能够明确的把每一个作为一个prop传进去:

<FillingHoleView width={60} height={60} radius={30} color={3} />

也能够应用style的形式,只是在本例须要在props里写出有style这个成员,否则会lint提醒error。

<FillingHoleView style={{ width: 100, height: 100 }} radius={100} color={1} />

最初

解决React Native的性能问题,或者复用原生代码的问题都须要用到原生视图的内容,当然也不会少了原生模块。

在开发的过程中除了步骤之外还要留神RN和原生视图的度量单位和宽高对flex布局的影响。

我的项目代码在这里。