John John - 5 months ago 26
Android Question

Calling a Android Native UI component method from React native Js code

I have created a CustomView SignatureView.java which extends LinearLayout for capturing signature in Android Native.

And created SignatureCapturePackage.java and SignatureCaptureViewManager.java

public class SignatureCaptureMainView extends LinearLayout {

....

public void saveImage(){
//Save image to file
}
}


this the Package class

public class SignatureCapturePackage implements ReactPackage {
private Activity mCurrentActivity;

public RSSignatureCapturePackage(Activity activity) {
mCurrentActivity = activity;
}

@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList();
}

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactApplicationContext) {
return Arrays.<ViewManager>asList(new SignatureCaptureViewManager(mCurrentActivity));
}

@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Arrays.asList();
}
}


this is the ViewManager class

public class SignatureCaptureViewManager extends ViewGroupManager<SignatureCaptureMainView> {
private Activity mCurrentActivity;

public static final String PROPS_SAVE_IMAGE_FILE="saveImageFileInExtStorage";
public static final String PROPS_VIEW_MODE = "viewMode";

public RSSignatureCaptureViewManager(Activity activity) {
mCurrentActivity = activity;
}

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

@ReactProp(name = PROPS_SAVE_IMAGE_FILE)
public void setSaveImageFileInExtStorage(SignatureCaptureMainView view, @Nullable Boolean saveFile) {
Log.d("React View manager setSaveFileInExtStorage:", "" + saveFile);
if(view!=null){
view.setSaveFileInExtStorage(saveFile);
}
}

@ReactProp(name = PROPS_VIEW_MODE)
public void setViewMode(SignatureCaptureMainView view, @Nullable String viewMode) {
Log.d("React View manager setViewMode:", "" + viewMode);
if(view!=null){
view.setViewMode(viewMode);
}
}

@Override
public SignatureCaptureMainView createViewInstance(ThemedReactContext context) {
Log.d("React"," View manager createViewInstance:");
return new SignatureCaptureMainView(context, mCurrentActivity);
}


}


This is Signature.js bundle

var React = require('react-native');
var {
PropTypes,
requireNativeComponent,
View,
} = React;

class SignatureCapture extends React.Component {

constructor() {
super();
this.onChange = this.onChange.bind(this);
}

onChange(event) {
console.log("Signature ON Change Event");
if (!this.props.onSaveEvent) {
return;
}

this.props.onSaveEvent({
pathName: event.nativeEvent.pathName,
encoded: event.nativeEvent.encoded,
});
}

render() {
return (
<SignatureView {...this.props} style={{flex: 1}} onChange={this.onChange} />
);
}

save(){

}
}

SignatureCapture.propTypes = {
...View.propTypes,
saveImageFileInExtStorage: PropTypes.bool,
viewMode:PropTypes.string
};

var SignatureView = requireNativeComponent('SignatureView', SignatureCapture, {
nativeOnly: {onChange: true}
});

module.exports = SignatureCapture;


I am using the Module in ReactNative like this

<SignatureCapture
onSaveEvent={this._onSaveEvent}
saveImageFileInExtStorage={false}
viewMode={"portrait"}/>


Everything worksFine. But i have to save the image only when some click event occurs in the react side. ie, i have to call SignatureCaptureMainView's saveImage() method from reactnative js code.

How can i achieve it ?.Please help

Answer

As per the pointer given by @agent_hunt.

check this blog for explaination

I have used ui manager commands in SignatureCaptureViewManager. Posting my solutions

public class SignatureCaptureViewManager extends ViewGroupManager<SignatureCaptureMainView> {
private Activity mCurrentActivity;

public static final String PROPS_SAVE_IMAGE_FILE="saveImageFileInExtStorage";
public static final String PROPS_VIEW_MODE = "viewMode";

public static final int COMMAND_SAVE_IMAGE = 1;


public SignatureCaptureViewManager(Activity activity) {
    mCurrentActivity = activity;
}

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

@ReactProp(name = PROPS_SAVE_IMAGE_FILE)
public void setSaveImageFileInExtStorage(SignatureCaptureMainView view, @Nullable Boolean saveFile) {
    Log.d("React View manager setSaveFileInExtStorage:", "" + saveFile);
    if(view!=null){
        view.setSaveFileInExtStorage(saveFile);
    }
}

@ReactProp(name = PROPS_VIEW_MODE)
public void setViewMode(SignatureCaptureMainView view, @Nullable String viewMode) {
    Log.d("React View manager setViewMode:", "" + viewMode);
    if(view!=null){
        view.setViewMode(viewMode);
    }
}

@Override
public SignatureCaptureMainView createViewInstance(ThemedReactContext context) {
    Log.d("React"," View manager createViewInstance:");
    return new SignatureCaptureMainView(context, mCurrentActivity);
}

@Override
public Map<String,Integer> getCommandsMap() {
    Log.d("React"," View manager getCommandsMap:");
    return MapBuilder.of(
            "saveImage",
            COMMAND_SAVE_IMAGE);
}

@Override
public void receiveCommand(
        SignatureCaptureMainView view,
        int commandType,
        @Nullable ReadableArray args) {
    Assertions.assertNotNull(view);
    Assertions.assertNotNull(args);
    switch (commandType) {
        case COMMAND_SAVE_IMAGE: {
            view.saveImage();
            return;
        }

        default:
            throw new IllegalArgumentException(String.format(
                    "Unsupported command %d received by %s.",
                    commandType,
                    getClass().getSimpleName()));
    }
}


}

For sending commands to ViewManager i have added this method in Signature Capture component

class SignatureCapture extends React.Component {

constructor() {
super();
this.onChange = this.onChange.bind(this);
}

onChange(event) {
console.log("Signature  ON Change Event");
if (!this.props.onSaveEvent) {
  return;
}

this.props.onSaveEvent({
  pathName: event.nativeEvent.pathName,
  encoded: event.nativeEvent.encoded,
});
 }

 render() {
  return (
   <SignatureView {...this.props} style={{flex: 1}} onChange=      {this.onChange} />
);
  }

saveImage(){
 UIManager.dispatchViewManagerCommand(
        React.findNodeHandle(this),
        UIManager.SignatureView.Commands.saveImage,
        [],
    );
   }
 }

SignatureCapture.propTypes = {
...View.propTypes,
rotateClockwise: PropTypes.bool,
square:PropTypes.bool,
saveImageFileInExtStorage: PropTypes.bool,
viewMode:PropTypes.string
};

  var SignatureView = requireNativeComponent('SignatureView',   SignatureCapture, {
 nativeOnly: {onChange: true}
 });

 module.exports = SignatureCapture;

This is how i am using SignatureCapture component in my parent Signature component

class Signature extends Component {

render() {

    return (
        <View style={{ flex: 1, flexDirection: "column" }}>

            <SignatureCapture
                style={{ flex: 8 }}
                ref="sign",
                onSaveEvent={this._onSaveEvent}
                saveImageFileInExtStorage={false}
                viewMode={"portrait"}/>

            <TouchableHighlight style={{ flex: 2 }}
                onPress={() => { this.saveSign() } } >
                <Text>Save</Text>
            </TouchableHighlight>

        </View>
    );
}
// Calls Save method of native view and triggers onSaveEvent callback
saveSign() {
    this.refs["sign"].saveImage();        
}

_onSaveEvent(result) {
    //result.encoded - for the base64 encoded png
    //result.pathName - for the file path name
    console.log(result);
  }

  }

 export default Signature;
Comments