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
If you're in the market for a professional-looking UI for your React Native iOS or Android apps, then the Shoutem UI kit is a great choice. Shoutem UI is an open source library that is a part of the Shoutem UI Tool Kit.
Unfortunately, the material-UI library specially built for ReactJS which is the web counterpart of the React Native is not applicable to the React Native app development ecosystem.
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;
                        I needed a solution that let me return values from my component instance method (Promises in my case).  Using receiveCommand didn't allow me to do this.
I was able to solve this using UIManagerModule.addUIBlock, similar to https://stackoverflow.com/a/31936516/194065:
public class MyViewModule extends ReactContextBaseJavaModule {
    public static final String TAG = MyViewModule.class.getSimpleName();
    public MyViewModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }
    @Override
    public String getName() {
        return "MyView";
    }
    @ReactMethod
    public void someMethod(final int viewId, final Promise promise) {
        withMyView(viewId, promise, new MyViewHandler() {
            @Override
            public void handle(MyView view) {
                String value = view.someMethod();
                promise.resolve(value)
            }
        });
    }
    private void withMyView(final int viewId, final Promise promise, final MyViewHandler handler) {
        UIManagerModule uiManager = getReactApplicationContext().getNativeModule(UIManagerModule.class);
        uiManager.addUIBlock(new UIBlock() {
            @Override
            public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
                View view = nativeViewHierarchyManager.resolveView(viewId);
                if (view instanceof MyView) {
                    MyView myView = (MyView) view;
                    handler.handle(myView);
                }
                else {
                    Log.e(TAG, "Expected view to be instance of MyView, but found: " + view);
                    promise.reject("my_view", "Unexpected view type");
                }
            }
        });
    }
}
Usage:
import React, { Component } from 'react';
import { NativeModules, requireNativeComponent, findNodeHandle } from "react-native";
const MyViewFunctions = NativeModules.MyView;
class MyView extends Component {
    someMethod() {
        MyViewFunctions.someMethod(findNodeHandle(this.nativeCmp));
    }
    render() {
        return (
            <RCTMyView
                ref={cmp => this.nativeCmp = cmp}
                {...this.props}
            />
        );
}
const RCMyView = requireNativeComponent('RCMyView', MyView);
export default MyView;
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With