Вызов метода компонента Native UI для Android из собственного кода React Js
Я создал CustomView SignatureView.java, который расширяет LinearLayout для захвата подписи в Android Native.
И создали SignatureCapturePackage.java и SignatureCaptureViewManager.java
public class SignatureCaptureMainView extends LinearLayout {
....
public void saveImage(){
//Save image to file
}
}
это класс Package
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();
}
}
это класс ViewManager
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);
}
}
Это пакет Signature.js
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;
Я использую модуль в ReactNative, как это
<SignatureCapture
onSaveEvent={this._onSaveEvent}
saveImageFileInExtStorage={false}
viewMode={"portrait"}/>
Все работает отлично. Но я должен сохранить изображение только тогда, когда на стороне реакции происходит какое-то нажатие. то есть, я должен вызвать метод saveImage() SignatureCaptureMainView из реактивного js-кода.
Как я могу достичь этого?
3 ответа
Согласно указателю, данному @agent_hunt.
проверьте этот блог для объяснения
Я использовал команды менеджера пользовательского интерфейса в SignatureCaptureViewManager. Размещение моих решений
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()));
}
}
}
Для отправки команд в ViewManager я добавил этот метод в компонент Signature Capture.
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;
Вот как я использую компонент SignatureCapture в моем родительском компоненте Signature
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;
Мне нужно решение, которое позволило бы мне возвращать значения из моего метода экземпляра компонента (Promises в моем случае). С помощью receiveCommand
не позволил мне сделать это.
Я смог решить это с помощью UIManagerModule.addUIBlock
, аналогично /questions/11994973/kak-poluchit-dostup-k-metodam-ekzemplyarov-nativnyih-komponentov-polzovatelskogo-interfejsa-v-react-native/11994979#11994979:
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");
}
}
});
}
}
Использование:
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;
Пожалуйста, смотрите инструкции для точно такой же проблемы на https://github.com/facebook/react-native/pull/4438