Using native attempts is an essential part of RN. If someone had done all the original functions, just used them or tweaked the parts that they were trying to use and didn’t have to build another set of wheels.

steps

The official documentation is very detailed. The direct quote is as follows:

Create a ViewManager subclass 2. Implement createViewInstance 3. Expose the properties of the view by annotating @reactProp or @ReactPropGroup 4. Register the manager in the createViewManagers method 5. Implementing JS modulesCopy the code

And the development of native modules of the basic process. First, however, you have to have a native view. It goes like this:

public class FillingHoleView extends View {
	// ...

    public float getRadius(a)
    public void setRadius(float radius)

    public int getStrokeColor(a)
    public void setStrokeColor(int color)

	onDraw

	onMeasure

	// ...
}
Copy the code

It’s just an Android view, let me draw a circle. You can control the color and radius of the circle through setters.

Then start adding code in the same order as above.

ViewManager subclass

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(a) {
        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); }}Copy the code

One advantage of using SimpleViewManager is that it provides background color, transparency, and Flex layout capabilities by default, as well as some accessbility. So inheriting the View Manager allows you to use flex layout.

View Manager implementation needs to provide the module name, in JS is also through the module name to obtain the native module.

The createViewInstance method returns the native view.

Properties that need to be exposed to JS are decorated with @reactProp or @ReactGroupProp annotations. The first parameter is your native view, and the second is the property to modify. Name is required. Only the value type of these attributes can provide a specific default value; reference types can only default to NULL.

Register the View Manager

Create a new package class if you don’t already have one:

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)
        );
    }

Copy the code

Inherit methods from ReactPackage to implement them. There are two main, one is registered native module, one is registered native view. This package then needs to be added to your Application class. See here.

Use your native view in JS

Simple version can refer to the official website:

// FillingHoleView.js

import { requireNativeComponent } from 'react-native';

/** * Composes `View`. * * - radius: number * - color: number * - width: number */
module.exports = requireNativeComponent('FillingHoleView');
Copy the code

React can be implemented as follows:

import React from 'react';
import { requireNativeComponent } from 'react-native';

const FillingNativeView = requireNativeComponent('FillingHoleView');

interface FillingHoleViewProps {
  radius: number;
  color: number; / / 1, 2, 3width? : number; }const FillingHoleView: React.FC<FillingHoleViewProps> = props= > {
  return <FillingNativeView {. props} / >;
};

export { FillingHoleView };

Copy the code

RequireNativeComponent returns components that can be used in other React components. What is missing, however, is a mandatory specification for receiving various properties and methods. So, wrapping a layer around it (without actually adding to the actual view hierarchy) can automatically indicate acceptable properties and so on in use.

There are also events that can be accepted, which can be referred to the official website. This will be added later.

layout

The example for this article is to draw a circle with adjustable background color and radius.

This is all about drawing logic, setting the radius with the setter, and then getting the width and height of the view (with the padding taken into account). As a result, there are some strange issues when executing the Flex layout in the view.

First, React units are not the same thing as Android units. For example, in this case, setting the width to 50 in Android code and 100 in JS will get 275 in Android (the values vary at different resolutions).

Therefore, in development, it is best to unify the wide and high entrance. For example, in this article it is best to use JS Settings and then calculate the radius of the circle from the width. The radius can also be set in JS, but the width is already set in measure, the radius is not, or is the default value in the example. As long as you’re on Android, the values you get here are different from those you get in JS (unless the resolution is right).

That’s the unit problem. Now there’s the matter of width.

The width must be there, otherwise the native view will have a width and height of 0 in the Flex layout system. As shown in figure:

The green circle is considered to be zero in width and height. Specific code:

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

The style of fillingNative is:

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

In this case the green circle is out of bounds and the text is displayed directly above it. Instead, see the yellow circle below set the width, but there is a problem with the units mentioned above, the layout is normal.

The problem with the red ball is that the width and height of the ball must be set in a way that the width and height of the ball must be specified. You can see that the red circle and white view have problems with the vertical layout. The problem is solved when the height is clearly given. As shown in figure:

Set the width and height, except that you can explicitly pass each as a prop:

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

You can also use the style method, but in this case you need to write the style member in props, otherwise lint will give an error.

<FillingHoleView style={{ width: 100.height: 100 }} radius={100} color={1} / >Copy the code

The last

React Native’s performance and reuse of Native code require Native views, as well as Native modules.

In addition to the steps, consider how the units of measure and width of RN and native views affect the Flex layout.

The project code is here.