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