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

前端 未结 3 1879
春和景丽
春和景丽 2021-02-08 09:06

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

And created SignatureCapturePackage.java and Signatu

相关标签:
3条回答
  • 2021-02-08 09:36

    Please see instructions for exactly similar problem at https://github.com/facebook/react-native/pull/4438#issuecomment-163533312

    0 讨论(0)
  • 2021-02-08 09:38

    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;
    
    0 讨论(0)
  • 2021-02-08 09:44

    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;
    
    0 讨论(0)
提交回复
热议问题