关于react-native:React-Native填坑之旅使用原生视图Android

82次阅读

共计 3943 个字符,预计需要花费 10 分钟才能阅读完成。

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

步骤

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

1. 新建一个 ViewManager 子类
2. 实现 createViewInstance 办法
3. 通过注解 @ReactProp 或者 @ReactPropGroup 裸露视图的属性
4. 在 createViewManagers 办法里注册这个 manager
5. 实现 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.js

import {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 布局的影响。

我的项目代码在这里。

正文完
 0