React Native: How to invoke native Android layout from module?

10.9k Views Asked by At

Regarding this question, I've been trying to get this done via native modules in Android.

I've declared my Module at .../java/com/myproject/multiplecamerastream following the example at React Native ToastModule (functionality here is not important):

public class MultipleCameraStreamModule extends ReactContextBaseJavaModule {

  private static final String CAMERA_FRONT = "SHORT";
  private static final String CAMERA_BACK = "LONG";

  public MultipleCameraStreamModule(ReactApplicationContext reactContext) {
    super(reactContext);
  }

  @Override
  public String getName() {
    return "MultipleCameraStream";
  }

  @Override
  public Map<String, Object> getConstants() {
    final Map<String, Object> constants = new HashMap<>();
    constants.put(CAMERA_FRONT, Toast.LENGTH_SHORT);
    constants.put(CAMERA_BACK, Toast.LENGTH_LONG);
    return constants;
  }

  @ReactMethod
  public void show(String message, int duration) {
    Toast.makeText(getReactApplicationContext(), message, duration).show();
  }
}

Then, my module packager:

public class MultipleCameraStreamPackage implements ReactPackage { 

  @Override
  public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
    return Collections.emptyList();
  }

  @Override
  public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
    List<NativeModule> modules = new ArrayList<>();
    modules.add(new MultipleCameraStreamModule(reactContext));
    return modules;
  }
}

I've been able to register it and to make it work. However, it only calls to a Toast in Android (no layout involved).

I'd like to set a layout, so when I call <MultipleCameraStream /> in JSX it renders a native Android layout, like the following:

/* .../multiplecamerastream/MultipleCameraStreamLayout.xml */
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
>
    <TextView android:id="@+id/multipleCameraText"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="Hello, I am a TextView" 
    />
    <Button android:id="@+id/multipleCameraButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello, I am a Button" 
    />
</LinearLayout>

How can I make that layout to be invoked from my module scripts (MultipleCameraStreamModule), and how can I make reference to its elements so I can interact with them from the Android module side programatically?

Thank you.

1

There are 1 best solutions below

8
On BEST ANSWER

There's explanation in the RN Native UI website itself, but I got lost in it too. :(

But here goes, let me know if there's improvement needed on this:

1) Create a View that will inflate your xml MultipleCameraStreamLayout.xml. Ideally, this CustomView can be used in Android pure code.

public class CustomView extends LinearLayout {
 private Context context;
 public CustomView(Context context) {
   super(context);//ADD THIS
   this.context = context;
 }
 ..
 public void init() {
   //modified here.
    inflate(context, R.layout.xxxxxxxxx, this);
  ...

2) Once set, put this into another class(View Manager) extending SimpleViewManager. Sample:

public class MyCustomReactViewManager extends SimpleViewManager<CustomView> {
   public static final String REACT_CLASS = "MyCustomReactViewManager";

   @Override
   public String getName() {
     return REACT_CLASS;
   }

   @Override
   public CustomView createViewInstance(ThemedReactContext context) {
     return new CustomView(context); //If your customview has more constructor parameters pass it from here.
   }

3) Now add it into the React package createViewManager method, you have created it in MultipleCameraStreamPackage. So, it'll be:

@Override
public List<ViewManager> createViewManagers(
        ReactApplicationContext reactContext) {
    return Arrays.<ViewManager>asList(
            new MyCustomReactViewManager() //Add here.
    );
}

4) You can now use the Android code, by reinstalling it

react-native run-android

5) Expose it in javascript. Create some file CustomView.js

import {requireNativeComponent, ViewPropTypes} from 'react-native';
//
module.exports = requireNativeComponent('MyCustomReactViewManager', null); //Add props are bit different.

6) Start using it into your views. Eg.

import CustomView from './CustomView.js';
...
render() {
 return 
  ...
  <CustomView style={{height:200, width:200}}/>
  ...;
}

Hope this helps.

If you need a code sample it's uploaded here.