今天我们来研究下RN
如何去调用iOS
的原生组件:
OC版
主要步骤
1、创建一个CropperMapViewBridge.m
桥接文件
2、在CropperMapViewBridge
里面创建一个RCTViewManager
的子类,来管理原生组件
3、创建原生组件
4、在RN
中调用原生组件
- 创建
RCTViewManager
的子类文件
#import <React/RCTBridgeModule.h>
#import <React/RCTViewManager.h>
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "CropperVieww.h"
@interface CropperMapViewManager: RCTViewManager
@end
@implementation CropperMapViewManager
// 将模块暴露给React端
RCT_EXPORT_MODULE()
// 设置属性 属性mapData 是从 RN 传来的参数
RCT_EXPORT_VIEW_PROPERTY(mapData,NSString)
// 设置回调方法 此回调方法主要是从原生回调去操作RN 的方法
// 注: 方法名前面一定要加上on 否则不会被执行
RCT_EXPORT_VIEW_PROPERTY(onFindMachineLocation, RCTBubblingEventBlock)
-(UIView *)view {
return [[CropperView alloc] initWithFrame: CGRectMake(0, 0, UIScreen.mainScreen.bounds.size.width - 24, UIScreen.mainScreen.bounds.size.width - 24)];
}
@end
RCT_EXPORT_MODULE()
是必须要写的-(UIView *)view
里面调用我们需要的UI组件
,里面的frame
可以不写,因为会被RN
里面设置的覆盖
- 创建原生
UI
组件
#import <UIKit/UIKit.h>
#import "React/RCTComponent.h"
@interface CropperView : UIView
// RN 组件传来的属性
@property(nonatomic, copy) NSString *mapData;
// 回调方法
@property(nonatomic, copy) RCTBubblingEventBlock onFaceDetection;
@end
#import "CropperView.h"
@implementation CropperView
- (instancetype)init
{
self = [super init];
if (self) {
self.backgroundColor = [UIColor redColor];
[self setUI];
}
return self;
}
- (void)setUI {
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 40, 50)];
button.backgroundColor = [UIColor grayColor];
[button addTarget:self action:@selector((find:)) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
}
- (void)find:(UIButton*)button {
// 回调函数 可传参
self.onFaceDetection(@{@"key": @"laoma"});
}
// 重写属性
// RN 部分的属性被赋值后会自动调用这个方法传参
- (void)setMapData:(NSString *)mapData {
NSLog(mapData);
}
@end
- 创建
RN
文件
import React ,{Component} from 'react'
import { requireNativeComponent } from 'react-native'
import PropTypes from 'prop-types';
var RECTMapView = requireNativeComponent('CropperMapView',CustomMapView, {nativeOnly: {}});
class CustomMapView extends Component{
static propTypes = {
// 属性 传给原生组件的参数 被赋值后悔自动调用原生的`mapData`的setter 方法
mapData: PropTypes.string,
};
constructor(props) {
super(props);
console.log(this.props.mapData)
}
// 查找设备位置
_findMachineLocation = (event) => {
console.log('');
console.log('_findMachineLocation');
console.log(event.nativeEvent);
};
render(){
return(
<RECTMapView {...this.props}
onFindMachineLocation={this._findMachineLocation}
/>
);
}
}
module.exports = CustomMapView
1
和2
为直接导出的组件名称,这俩名称必须一致3
为原生组件的名称CropperMapViewManager
,调用的时候会自动补全后面的Manager
。这个字段一定要和CropperMapViewManager
的Manager
前面的名字保持一致。4
和5
为RN
模块的名称,这俩也得保持一致mapData
这个属性要和原生的View中的属性保持一致onFindMachineLocation
这个回调方法名称也的和原生的保持一致
Swift版本
核心步骤跟OC
版的一样,不同的是CropperMapViewManager
里面调用CropperView
的方法不一样,UI
组件的设置参数和回调方法不一样。
CropperMapViewManager
#import <React/RCTBridgeModule.h>
#import <React/RCTViewManager.h>
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
// Swift 和 OC 混编需要这样调用swift文件
#import <TBCropperMapModule/TBCropperMapModule-Swift.h>
@interface CropperMapView: RCTViewManager
@end
@implementation CropperMapView
// 将模块暴露给React端
RCT_EXPORT_MODULE()
// 设置属性 属性mapData 是从 RN 传来的参数
RCT_EXPORT_VIEW_PROPERTY(mapData,NSString)
// 设置回调方法 此回调方法主要是从原生回调去操作RN 的方法
RCT_EXPORT_VIEW_PROPERTY(onFindMachineLocation, RCTBubblingEventBlock)
-(UIView *)view {
return [[CropperView alloc] initWithFrame: CGRectMake(0, 0, UIScreen.mainScreen.bounds.size.width - 24, UIScreen.mainScreen.bounds.size.width - 24)];
}
@end
#import <TBCropperMapModule/TBCropperMapModule-Swift.h>
因为我是用的组件模块开发,所以这样调用。通常情况下OC
调用Swift文件,直接#imp
UI
组件
import UIKit
import SnapKit
import React
public class CropperView: UIView {
private var mapView:BitMapView = BitMapView(frame: CGRect(x: 0, y: 0, width: 78, height: 76))
// RN 传过来的参数
@objc
var mapData: String = "" {
didSet {
print(mapData)
self.updateMapView()
}
}
// 回调函数
@objc
var onFindMachineLocation: RCTBubblingEventBlock?
func setMapData(mapData: String) {
print(mapData)
}
override public init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .green
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc
func findMachine() {
self.onFindMachineLocation!(["key":"laomma"])
}
private func setMapView() {
let mapView = UIView()
mapView.frame = CGRect(x: 10, y: 10, width: 10, height: 10)
mapView.backgroundColor = .red
self.addSubview(mapView)
}
}
注:
属性mapData
和回调参数self.onFindMachineLocation
都需要加上@objc
修饰,不然不起作用。