封装IOS原生组件——导出组件事件到RN端使用
导出IOS原生组件的事件到RN端的步骤。
1、在IOS组件的头文件声明一个事件属性。
2、在RN组件桥接类里面导出这个事件属性。
3、在IOS原生端通过定义的事件属性发送事件到RN端。
4、在RN端封装IOS原生组件事件。
1、在IOS组件的头文件声明一个事件属性
TestReactNativeView.h
// // TestReactNativeView.h // NativeCommunicationDemo // // Created by chenlw on 2019/4/10. // Copyright © 2019 Facebook. All rights reserved. // #import <UIKit/UIKit.h> #import "React/RCTComponent.h" NS_ASSUME_NONNULL_BEGIN @interface TestReactNativeView : UIView // type操作类型 @property(nonatomic,weak) NSString * type; //如果使用assign会导致线程锁死,使用weak弱引用就没有问题 //@property(nonatomic,assign) UITextView *textView; @property(nonatomic,weak) UITextView *textView; // 声明一个事件属性,导出给RN端使用 @property(nonatomic, copy) RCTBubblingEventBlock onFaceDetection; @end NS_ASSUME_NONNULL_END
2、在RN组件桥接类导出这个事件属性
TestReactNativeViewManager.m
// // TestReactNativeViewManager.m // NativeCommunicationDemo // // Created by chenlw on 2019/4/10. // Copyright © 2019 Facebook. All rights reserved. // #import "TestReactNativeViewManager.h" #import "TestReactNativeView.h" @implementation TestReactNativeViewManager //导出桥接宏标记 RCT_EXPORT_MODULE() //导出RN组件的属性 RCT_EXPORT_VIEW_PROPERTY(type, NSString) //导出RN组件的事件 RCT_EXPORT_VIEW_PROPERTY(onFaceDetection, RCTBubblingEventBlock) - (UIView *)view { //创建组件实例 TestReactNativeView * viewInstance =[[TestReactNativeView alloc] init]; return viewInstance; } @end
3、在IOS原生端通过定义的事件属性发送事件到RN端
模拟场景:在IOS原生自定义组件上添加一个按钮,点击按钮的时候,往RN发送事件。
这里,我们通过一个按钮的点击事件来发送事件到RN端。
TestReactNativeView.m
// // TestReactNativeView.m // NativeCommunicationDemo // // Created by chenlw on 2019/4/10. // Copyright © 2019 Facebook. All rights reserved. // #import "TestReactNativeView.h" //ReactNative封装IOS原生组件,这里编写一个测试用的组件类 @implementation TestReactNativeView /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ - (instancetype)init { //初始化组件 self = [super init]; if (self) { self.backgroundColor = [UIColor redColor]; } //创建一个文本组件 UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(20,20,300,40)]; //设置文字 textView.text = @"IOS原生组件"; //设置字体大小 [textView setFont:[UIFont systemFontOfSize:20]]; //添加文件组件 [self addSubview:textView]; self.textView = textView; //创建一个按钮组件 UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; button.frame = CGRectMake(20, 80, 100, 40); [button setTitle:@"发送事件到RN" forState:UIControlStateNormal]; // [button addTarget:self action:@selector(sendEventToReactNative) forControlEvents:UIViewNoIntrinsicMetric]; /** * addTarget:目标(让谁做这个事情) * action:方法(做什么事情-->方法) * forControlEvents:事件 */ [button addTarget:self action:@selector(sendEventToReactNative:) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:button]; //[self bringSubviewToFront:button]; return self; } //重写设置属性方法,当RN端设置type属性,就会调用这个方法 -(void)setType:(NSString *)type{ NSLog(@"setType"); self.textView.text = type; //self.type = type; } //按钮的响应事件 - (void)sendEventToReactNative:(UIButton *)button{ NSLog(@"sendEventToReactNative"); //往RN端发送事件 self.onFaceDetection(@{@"faceBase64":@"IOS原生端回传的数据"}); } @end
4、在RN端封装IOS原生组件事件
在RN组件内部,对这个事件进行封装处理,过滤掉对RN端无用的参数。
'use strict'; import React, {Component} from 'react'; import PropTypes from 'prop-types'; import { requireNativeComponent, View, } from 'react-native'; const TestReactNativeView = requireNativeComponent('TestReactNativeView', TestReactNativeViewComponent , {nativeOnly: {}}); //对封装的组件进行二次封装 class TestReactNativeViewComponent extends Component { constructor(props) { super(props); } /** * 对IOS组件的事件进行处理,解析对RN端有用的参数 * @param event * @private */ _onFaceDetection = (event) => { if (!this.props.onFaceDetection) { return; } console.log(''); console.log('_onFaceDetection'); console.log(event.nativeEvent); this.props.onFaceDetection(event.nativeEvent.faceBase64); }; render() { return ( <TestReactNativeView {...this.props} onFaceDetection={this._onFaceDetection} /> ); } } TestReactNativeViewComponent.propTypes = { type: PropTypes.string, onFaceDetection: PropTypes.func, ...View.propTypes, }; //导出二次封装的组件 module.exports = TestReactNativeViewComponent;
5、测试页面
import React, {Component} from 'react'; import {Dimensions, StyleSheet, View} from 'react-native'; import TestReactNativeView from './TestReactNativeView'; const screenWidth = Dimensions.get('window').width; /** * IOS原生组件封装,注意RN端设置组件的宽度和高度,这样组件才能显示。 */ export default class TestReactNativeViewExample extends Component { static navigationOptions = { headerTitle: 'IOS原生组件封装example', }; constructor(props, context) { super(props, context); } render() { return ( <View style={styles.container}> <TestReactNativeView style={{ flex: 1, width: screenWidth, }} type={'type from react-native'} onFaceDetection={(faceBase64) => { console.log(''); console.log('TestReactNativeViewExample.TestReactNativeView'); console.log(faceBase64); alert('RN端接收到IOS原生端发送的事件:'+faceBase64); }} /> </View> ) } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', } });
6、运行效果