React-Native UI Native components in Swift and Java
Carlos Thurber
Technical
React Native already provides the basic components you would use to build your application: views, labels, buttons, tables, etc.
However, there are times when these components aren't enough. In this tutorial we’ll explain how we build our own native component that can send messages back and forth between Javascript and the iOS/Android code.
Note: Most tutorials focus on how to do this in Objective-C, but we'll be using Swift instead.
We will also be using Xcode 10.2 and Android Studio 3.3.2, running in Mac OS 10.14.4
Building the Demo application
Make sure you have the React Native CLI installed:
npm install -g react-native-cli
Next, let's create our project
react-native init AwesomeProject
And now let's run our application
react-native run-ios --simulator="iPhone 12"
Creating a Native UI Component
iOS
Open AwesomeProject/ios/AwesomeProject.xcodeproj in Xcode
Defining out custom view in iOS
Create a new file: File -> New -> File... -> Cocoa Touch Class
Note: When asked, choose Create Bridging Header.
Patch for SWIFT Development
Since React-Native was built with ObjectiveC in mind, we need to do some tricks to be able to make it work with Swift.
First let's create the same file, but in ObjectiveC
And delete the MyCustomView.h since we won't be using it.
Select the file AwesomeProject-Bridging-Header.hand add this content:
#import
#import
#import
#import
#import
#import
Defining our view
Open MyCustomView.swift and paste the following code to define our view:
class MyCustomView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
private func setupView() {
// in here you can configure your view
}
}
Besides this view, we also need an RCTViewManager subclass that will be the one creating and manipulating this view.
Now, the only thing missing is to let ReactNative know about this manager. In order to do this, open MyCustomView.m and replace it's content with the following:
Import AwesomeProject/android/ into Android Studio
Defining our custom view in Android
Create a new file: File -> New -> File... and name it MyCustomView.java
Open MyCustomView.java and paste the following code to define our view:
public class MyCustomView extends RelativeLayout {
public MyCustomView(Context context) {
super(context);
}
public MyCustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MyCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void onFinishInflate(){
super.onFinishInflate();
}
}
Besides this view, we also need a view manager that will be the one creating and manipulating this view.
Create a file called MyCustomViewManager.java and paste the following :
public class MyCustomViewManager extends SimpleViewManager {
public static final String REACT_CLASS = "RCTMyCustomView";
String eventName = "onClick";
@Override
public String getName() { return REACT_CLASS; }
@Override
public MyCustomView createViewInstance(ThemedReactContext context) {
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
MyCustomView view = (MyCustomView)inflater.inflate(R.layout.custom_view, null);
return view;
}
}
Now, the only thing missing is to let ReactNative know about this manager. To do this, create a file called MyCustomViewReactPackage.java and paste the following:
public class MyCustomViewReactPackage implements ReactPackage {
@Override
public List createViewManagers(ReactApplicationContext reactContext) {
return Arrays.asList( new MyCustomViewManager() );
}
@Override
public List createNativeModules(ReactApplicationContext reactContext) {
List modules = new ArrayList<>();
return modules;
}
}
In the MainApplication.java file in your project let's add the MyCustomViewReactPackage like this:
public class MainApplication extends Application implements ReactApplication {
...
@Override
protected List getPackages() {
return Arrays.asList(
new MainReactPackage(),
new MyCustomViewReactPackage() // new line!!!
);
}
@Override
protected String getJSMainModuleName() {
return "index";
}
}
Adding properties to our custom view
Now, let's bridge over some native properties. For this, we'll create the same prop and function like in iOS.
Open MyCustomView.java and add this to your class:
Observe how in onClick() we will send an event to Javascript but we still need the connections of the status prop and the onClickEvent to react-native. In order to do this, open the MyCustomViewManager.java and paste the following:
In Javascript we map the native views RCTMyCustomView into our MyCustomView component using the requireNativeComponent function. It receives two props: a simple boolean value called status and a function called onClick. The two props are defined in iOS and Android respectively.
Once the onClick event is triggered natively it will call the mapped prop to switch the status props coming into the MyCustomView.