这两天在做一个插件,RN 调用iOS 端封装的一个Vew,需要对这个view 进行点击操作,跳转到横屏进行处理。经实验发现,iOS端,在view 外面包一个<TouchableOpacity>可以实现view 的点击透传,但andriod 端不起作用,为了和andriod 端保持一致,所以学习了下事件的传递。
下面以一个Demo,进行说明,由于是新手,难免会有理解不当,如有错,望前辈们指点一下。
该Demo 主要实现的功能是初始根据JS 端给的初值,调用Xcode 端图片,生成view,并旋转90度(这里只是想记忆一下view 旋转90度的方法),然后点击图片,并传message给JS,在JS端重新刷新页面,改变text 值,这个传来的值,也会以warn 的形式显示。
1.首先在Xcode 创建四个文件,并放两个图片名为"one.jpg"和"two.jpg"
- BridgeView.h代码如下:其中propertyArr初值会从JS端传过来。
#import <UIKit/UIKit.h>
#import <React/RCTComponent.h>
NS_ASSUME_NONNULL_BEGIN
@interface BridgeView : UIImageView
@property (nonatomic,strong)NSArray *propertyArr;
@property(nonatomic,strong)RCTBubblingEventBlock onClick;
@end
NS_ASSUME_NONNULL_END
- BridgeView.m代码如下:根据propertyArr设置View 显示哪张图片以及是否旋转90度。在封装的view 里添加了一个点击事件,通过此事件把message信息传给JS。
#import "BridgeView.h"
@implementation BridgeView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(doClick)];
[self addGestureRecognizer:gesture];
}
return self;
}
- (void)doClick {
if(self.onClick)
{
self.onClick(@{@"message":@"我是Native传过来的值"});
}
}
- (void)setPropertyArr:(NSArray *)propertyArr {
_propertyArr = propertyArr;
if (propertyArr.count == 2) {
if ([propertyArr.firstObject isEqualToString:@"one"] && [propertyArr.lastObject isEqualToString:@"nomal"]) {
UIImage *image = [UIImage imageNamed:@"one"];
self.image = image;
} else { //第二张图片旋转90度
self.image = [UIImage imageNamed:@"two"];
self.transform = CGAffineTransformMakeRotation(M_PI*90/180);
}
}
}
@end
- BridgeViewManager.h是继承于 RCTViewManager
#import <React/RCTViewManager.h>
NS_ASSUME_NONNULL_BEGIN
@interface BridgeViewManager : RCTViewManager
@end
NS_ASSUME_NONNULL_END
- 在BridgeViewManager.m里
#import "BridgeViewManager.h"
#import "BridgeView.h"
@implementation BridgeViewManager
RCT_EXPORT_MODULE()
RCT_EXPORT_VIEW_PROPERTY(propertyArr,NSArray)
RCT_EXPORT_VIEW_PROPERTY(onClick, RCTBubblingEventBlock)
- (UIView *)view {
return [[BridgeView alloc]init];
}
@end
2.在JS 端创建reactView.js 文件,引入xcode 端创建的BridgeView文件,
需要说明的两点:
(1)为了更直观的说明点击了原生的view,从原生端传过来了一个"message",并赋值给了状态属性isone,重新刷新了页面,原生端传过来的信息就显示在了界面上。
(2)引入这句话import PropTypes from 'prop-types'的前提是进入项目根目录,执行如下代码安装 prop-types 库:
npm install --save prop-types
- 创建reactView.js 文件:
import React,{ Component } from 'react';
import PropTypes from 'prop-types';
import { requireNativeComponent,Text,View,StyleSheet } from 'react-native';
var BridgeView = requireNativeComponent('BridgeView',AridgeVie); //引入原生文件
export default class AridgeView extends Component {
constructor(props) {
super(props);
this.state = { isone: "one" };
}
static propTypes = {
propertyArr:PropTypes.array,
};
_onChange = (event) => {
console.warn(`${event.nativeEvent["message"]}`,);
this.setState({
isone :`${event.nativeEvent["message"]}`
});
}
render() {
return (
<View>
<BridgeView style = {styles.bridgeViewStyle} {...this.props} onClick={this._onChange}/>
<Text style = {styles.textStyle}>{this.state.isone}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
bridgeViewStyle: {
marginHorizontal:50,
height:400,
marginTop:200
},
textStyle: {
marginHorizontal:50,
height:50,
marginTop:50,
fontSize:20,
color:'red',
fontWeight:'bold',
},
})
值得一提的是:
var BridgeView = requireNativeComponent('BridgeView',AridgeVie);
第二个参数是封装的组件AridgeVie,官网上说,这使得 React Native 的底层框架可以检查原生属性和包装类的属性是否一致,来减少出现问题的可能。===没理解。
- 在App.js 引入刚刚创建的reactView.js,并赋初值propertyArr = {["two","nomal"]。
import React, { Component } from 'react';
import ReactView from "./reactView"
import {
StyleSheet,
Dimensions,
} from "react-native";
export default class App extends Component {
constructor(props) {
super(props)
}
render() {
return (
<ReactView style={styles.imageViewStyle} propertyArr = {["two","nomal"]} ></ReactView>
);
}
}
const styles = StyleSheet.create({
imageViewStyle: {
backgroundColor: "white",
marginLeft:50,
marginTop: 100,
width: Dimensions.get('window').width - 100,
height: 400
},
});
3.最后结果为:
初始界面为图片旋转了90度
当点击了图片后,native值传到了JS进行了显示:
在做项目中遇到的坑:
这期间参考了这篇博主的文章:参考Demo
原作者是封装了一个button,通过点击button ,改变button 的标题。button 的点击事件是直接写在CLFButtonManager.m里的,起初,我照着作者的思路,把view 的点击事件也直接写在了BridgeViewManager.m里,可是结果是:我在项目里,点击图片跳转到横屏,再回到这个页面后,再点击图片发现没反应了,andriod 是没问题的,和同事在JS端查代码好久,最后有个同事告诉我我xcode 代码写得有问题,在BridgeViewManager.m写gesture 事件只能点一次,后来改成上面的写法就ok 了。其实,还是没理解,谁叫渣呢。