原生开发,发展到今天已经非常成熟完善,已有组件成千上万,极大的提高了开发效率。而React Native 在Facebook的React.js conf 2015上提出,至今一年多,组件数目肯定没得和原生的相比。
因此,在使用React Native开发App的过程中,我们可能需要调用RN没有实现的原生视图组件或第三方组件。甚至,我们可以把本地模块构造成一个React Native组件,提供给别人使用。
本文的demo基于SDCycleScrollView,即banner,因为想不到什么好的例子,所以就把在做的项目用到的SDCycleScrollView封装下,直接给js调用。
SDCycleScrollView为github开源的无限循环自动图片轮播器。
地址为:https://github.com/gsdios/SDCycleScrollView
里面会用SDWebImage,如果项目已用到SDWebImage,则建议直接把SDCycleScrollView相关代码拉进项目就OK了。
参考其他人对原生视图的封装,大多都会新建一个视图,继承(或者子视图包含)原生视图,里面可能含有事件的调用(这里简单demo,就没用到)。
#import "UIView+React.h",对原生视图进行扩展(这里有个重要的属性reactTag,后面会用到,作为区分用途)。
#import "SDCycleScrollView.h"
#import "RCTComponent.h"
#import "UIView+React.h"
@interface TestScrollView : SDCycleScrollView
@property (nonatomic, copy) RCTBubblingEventBlock onClickBanner;
@end
在封装的UIView中声明RCTBubblingEventBlock或RCTBubblingEventBlock类型的block属性,才可以被当做事件导出。(新的事件导出方式,后面会用到哦)
注意:声明block属性名称要以on开头(不确定为什么,在不做其它配置的情况下,只有on开头能成功)
#import "TestScrollView.h"
@implementation TestScrollView
/**
* 挺多封装原生的第三方组件都会这么写,这里还没研究透彻,就没按着去实现
- (instancetype)initWithBridge:(RCTBridge *)bridge {
if ((self = [super initWithFrame:CGRectZero])) {
_eventDispatcher = bridge.eventDispatcher;
_bridge = bridge;
......
}
return self;
}
*/
@end
原生视图都需要被一个RCTViewManager的子类来创建和管理。
这些管理器在功能上有些类似“视图控制器”,但它们本质上都是单例 - React Native只会为每个管理器创建一个实例。
它们创建原生的视图并提供给RCTUIManager,RCTUIManager则会反过来委托它们在需要的时候去设置和更新视图的属性。RCTViewManager还会代理视图的所有委托,并给JavaScript发回对应的事件。
提供原生视图步骤如下:
下面先贴出完整的代码,然后会对属性和事件进行进一步的解说。
#import "RCTViewManager.h"
@interface TestScrollViewManager : RCTViewManager
@end
#import "TestScrollViewManager.h"
#import "TestScrollView.h" //第三方组件的头文件
#import "RCTBridge.h" //进行通信的头文件
#import "RCTEventDispatcher.h" //事件派发,不导入会引起Xcode警告
@interface TestScrollViewManager() <SDCycleScrollViewDelegate>
@end
@implementation TestScrollViewManager
// 标记宏(必要)
RCT_EXPORT_MODULE()
// 事件的导出,onClickBanner对应view中扩展的属性
RCT_EXPORT_VIEW_PROPERTY(onClickBanner, RCTBubblingEventBlock)
// 通过宏RCT_EXPORT_VIEW_PROPERTY完成属性的映射和导出
RCT_EXPORT_VIEW_PROPERTY(autoScrollTimeInterval, CGFloat);
RCT_EXPORT_VIEW_PROPERTY(imageURLStringsGroup, NSArray);
RCT_EXPORT_VIEW_PROPERTY(autoScroll, BOOL);
- (UIView *)view
{
// 实际组件的具体大小位置由js控制
TestScrollView *testScrollView = [TestScrollView cycleScrollViewWithFrame:CGRectZero delegate:self placeholderImage:nil];
// 初始化时将delegate指向了self
testScrollView.pageControlStyle = SDCycleScrollViewPageContolStyleClassic;
testScrollView.pageControlAliment = SDCycleScrollViewPageContolAlimentCenter;
return testScrollView;
}
/**
* 当事件导出用到 sendInputEventWithName 的方式时,会用到
- (NSArray *) customDirectEventTypes {
return @[@"onClickBanner"];
}
*/
#pragma mark SDCycleScrollViewDelegate
/**
* banner点击
*/
- (void)cycleScrollView:(TestScrollView *)cycleScrollView didSelectItemAtIndex:(NSInteger)index
{
// 这也是导出事件的方式,不过好像是旧方法了,会有警告
// [self.bridge.eventDispatcher sendInputEventWithName:@"onClickBanner"
// body:@{@"target": cycleScrollView.reactTag,
// @"value": [NSNumber numberWithInteger:index+1]
// }];
if (!cycleScrollView.onClickBanner) {
return;
}
NSLog(@"oc did click %li", [cycleScrollView.reactTag integerValue]);
// 导出事件
cycleScrollView.onClickBanner(@{@"target": cycleScrollView.reactTag,
@"value": [NSNumber numberWithInteger:index+1]});
}
// 导出枚举常量,给js定义样式用
- (NSDictionary *)constantsToExport
{
return @{
@"SDCycleScrollViewPageContolAliment": @{
@"right": @(SDCycleScrollViewPageContolAlimentRight),
@"center": @(SDCycleScrollViewPageContolAlimentCenter)
}
};
}
// 因为这个类继承RCTViewManager,实现RCTBridgeModule,因此可以使用原生模块所有特性
// 这个方法暂时没用到
RCT_EXPORT_METHOD(testResetTime:(RCTResponseSenderBlock)callback) {
callback(@[@(234)]);
}
@end
RCT_EXPORT_VIEW_PROPERTY(autoScrollTimeInterval, CGFloat);
通过宏RCT_EXPORT_VIEW_PROPERTY完成属性的映射和导出。
CGFloat为autoScrollTimeInterval的OC数据类型,转化成js则对应number。
React Native用RCTConvert来在JavaScript和原生代码之间完成类型转换。
支持的默认转换类型(部分)如下:
如果转换无法完成,会产生一个“红屏”的报错提示,这样你就能立即知道代码中出现了问题。如果一切进展顺利,上面这个宏就已经包含了导出属性的全部实现。
ps:更复杂的类型转换,则涉及到MKCoordinateRegion类型,本文没做应用,具体可参考官方文档例子。
js和原生之间需要有事件的交互,例如,在原生实现的代理或者点击事件,js也需要实时获取到此类事件时,就需要利用事件进行交互。
事件的实现方式有以下两种:
通过sendInputEventWithName实现
1) 实现customDirectEventTypes,返回自定义的事件名数组(on开头才有效)
- (NSArray *) customDirectEventTypes {
return @[@"onClickBanner"];
}
2) sendInputEventWithName实现事件调用(reactTag用于实例的区分)
[self.bridge.eventDispatcher sendInputEventWithName:@"onClickBanner"
body:@{@"target": cycleScrollView.reactTag,
@"value": [NSNumber numberWithInteger:index+1]
}];
通过RCTBubblingEventBlock实现
1) 在封装的View中添加RCTBubblingEventBlock的block属性(on开头才有效)
@property (nonatomic, copy) RCTBubblingEventBlock onClickBanner;
2) 在Manager类中通过宏RCT_EXPORT_VIEW_PROPERTY完成Block属性的映射和导出
RCT_EXPORT_VIEW_PROPERTY(onClickBanner, RCTBubblingEventBlock)
3) 实现事件调用(reactTag用于实例的区分)
cycleScrollView.onClickBanner(@{@"target": cycleScrollView.reactTag,
@"value": [NSNumber numberWithInteger:index+1]});
通过上面两种方式封装好的事件,在js中可以直接利用同名函数调用即可(后面会展示)。
不过关于事件这块,挺多都没完全弄懂,希望有大神引导引导,比如为什么只能定义on开头、如何自定义、如何事件数据源的回调等等。。。
因为我们所有的视图都是UIView的子类,大部分的样式属性应该直接就可以生效。有些属性定义,需要用到枚举,则可以利用通过原生传递来的常数方式来实现,具体实现如下:
// 导出枚举常量,给js定义样式用
- (NSDictionary *)constantsToExport
{
return @{
@"SDCycleScrollViewPageContolAliment": @{
@"right": @(SDCycleScrollViewPageContolAlimentRight),
@"center": @(SDCycleScrollViewPageContolAlimentCenter)
}
};
}
在js中调用则如下:
// 首先获取到常量
var TestScrollViewConsts = require('react-native').UIManager.TestScrollView.Constants;
// 调用
ps: 一部分组件会希望使用自己定义的默认样式,例如UIDatePicker希望自己的大小是固定的。比如大小用原生默认大小,这个例子具体可以参考官方文档的样式模块。
在js中调用,可以有两种方式,一为直接作为扩展React组件调用,二为新建一个组件封装好,再进行调用。
下文用第二种方式,官方推荐,逻辑比较清晰。
1.先倒入原生组件,新建TestScrollView.js文件,在里面对TestScrollView导入,进行属性类型声明等。具体代码和解释如下:
// TestScrollView.js
import React, { Component, PropTypes } from 'react';
import { requireNativeComponent } from 'react-native';
// requireNativeComponent 自动把这个组件提供给 "RCTScrollView"
var RCTScrollView = requireNativeComponent('TestScrollView', TestScrollView);
export default class TestScrollView extends Component {
render() {
return <RCTScrollView {...this.props} />;
}
}
TestScrollView.propTypes = {
/**
* 属性类型,其实不写也可以,js会自动转换类型
*/
autoScrollTimeInterval: PropTypes.number,
imageURLStringsGroup: PropTypes.array,
autoScroll: PropTypes.bool,
onClickBanner: PropTypes.func
};
module.exports = TestScrollView;
2.在index.ios.js中进行调用
var TestScrollView = require('./TestScrollView');
// requireNativeComponent 自动把这个组件提供给 "TestScrollView"
// 如果不新建TestScrollView.js对原生组件封装声明,则直接用这句导入即可
// var TestScrollView = requireNativeComponent('TestScrollView', null);
// 导入常量
var TestScrollViewConsts = require('react-native').UIManager.TestScrollView.Constants;
var bannerImgs = [
'http://upload-images.jianshu.io/upload_images/2321678-ba5bf97ec3462662.png?imageMogr2/auto-orient/strip%7CimageView2/2',
'http://upload-images.jianshu.io/upload_images/1487291-2aec9e634117c24b.jpeg?imageMogr2/auto-orient/strip%7CimageView2/2/w/480/q/100',
'http://f.hiphotos.baidu.com/zhidao/pic/item/e7cd7b899e510fb37a4f2df3db33c895d1430c7b.jpg'
];
class NativeUIModule extends Component {
constructor(props){
super(props);
this.state={
bannerNum:0
}
}
render() {
return (
<ScrollView style = {{marginTop:64}}>
<View>
<TestScrollView style={styles.container}
autoScrollTimeInterval = {2}
imageURLStringsGroup = {bannerImgs}
pageControlAliment = {TestScrollViewConsts.SDCycleScrollViewPageContolAliment.right}
onClickBanner={(e) => {
console.log('test' + e.nativeEvent.value);
this.setState({bannerNum:e.nativeEvent.value});
}}
/>
<Text style={{fontSize: 15, margin: 10, textAlign:'center'}}>
点击banner -> {this.state.bannerNum}
Text>
View>
ScrollView>
);
}
}
// 实际组件的具体大小位置由js控制
const styles = StyleSheet.create({
container:{
padding:30,
borderColor:'#e7e7e7',
marginTop:10,
height:200,
},
});
AppRegistry.registerComponent('NativeTest2', () => NativeUIModule);
若使用第一种方式,即使用下面语句进行组件的引用:
var TestScrollView = requireNativeComponent('TestScrollView', null);
则会存在的这样的问题:
虽然很方便简单,但这样并不能很好的说明这个组件的用法——用户要想知道我们的组件有哪些属性可以用,以及可以取什么样的值,他不得不一路翻到Objective-C的代码。要解决这个问题,我们可以创建一个封装组件,并且通过PropTypes来说明这个组件的接口。
注意:我们现在把requireNativeComponent的第二个参数从null变成了用于封装的组件TestScrollView。这使得React Native的底层框架可以检查原生属性和包装类的属性是否一致,来减少出现问题的可能。
关于属性、事件的调用,则是如下直接调用:
2}
imageURLStringsGroup = {bannerImgs}
pageControlAliment = {TestScrollViewConsts.SDCycleScrollViewPageContolAliment.right}
onClickBanner={(e) => {
console.log('test' + e.nativeEvent.value);
this.setState({bannerNum:e.nativeEvent.value});
}}
/>
关于事件,需要注意的是,事件事件默认传递的是字典数据类型,即json,在js中调用需要利用e.nativeEvent才能将字典取出,在具体调用里面的值。(这里也还未研究透彻、需要指导)
React Native 与原生代码之间混合互相调用。经典项目如下:
链接: https://pan.baidu.com/s/1kVwRnYB 密码: vuwz
原生开发,发展到今天已经非常成熟完善,已有组件成千上万,极大的提高了开发效率。而React Native 在Facebook的React.js conf 2015上提出,至今一年多,组件数目肯定没得和原生的相比。
因此,在使用React Native开发App的过程中,我们可能需要调用RN没有实现的原生视图组件或第三方组件。甚至,我们可以把本地模块构造成一个React Native组件,提供给别人使用。
本文的demo基于SDCycleScrollView,即banner,因为想不到什么好的例子,所以就把在做的项目用到的SDCycleScrollView封装下,直接给js调用。
SDCycleScrollView为github开源的无限循环自动图片轮播器。
地址为:https://github.com/gsdios/SDCycleScrollView
里面会用SDWebImage,如果项目已用到SDWebImage,则建议直接把SDCycleScrollView相关代码拉进项目就OK了。
参考其他人对原生视图的封装,大多都会新建一个视图,继承(或者子视图包含)原生视图,里面可能含有事件的调用(这里简单demo,就没用到)。
#import "UIView+React.h",对原生视图进行扩展(这里有个重要的属性reactTag,后面会用到,作为区分用途)。
#import "SDCycleScrollView.h"
#import "RCTComponent.h"
#import "UIView+React.h"
@interface TestScrollView : SDCycleScrollView
@property (nonatomic, copy) RCTBubblingEventBlock onClickBanner;
@end
在封装的UIView中声明RCTBubblingEventBlock或RCTBubblingEventBlock类型的block属性,才可以被当做事件导出。(新的事件导出方式,后面会用到哦)
注意:声明block属性名称要以on开头(不确定为什么,在不做其它配置的情况下,只有on开头能成功)
#import "TestScrollView.h"
@implementation TestScrollView
/**
* 挺多封装原生的第三方组件都会这么写,这里还没研究透彻,就没按着去实现
- (instancetype)initWithBridge:(RCTBridge *)bridge {
if ((self = [super initWithFrame:CGRectZero])) {
_eventDispatcher = bridge.eventDispatcher;
_bridge = bridge;
......
}
return self;
}
*/
@end
原生视图都需要被一个RCTViewManager的子类来创建和管理。
这些管理器在功能上有些类似“视图控制器”,但它们本质上都是单例 - React Native只会为每个管理器创建一个实例。
它们创建原生的视图并提供给RCTUIManager,RCTUIManager则会反过来委托它们在需要的时候去设置和更新视图的属性。RCTViewManager还会代理视图的所有委托,并给JavaScript发回对应的事件。
提供原生视图步骤如下:
下面先贴出完整的代码,然后会对属性和事件进行进一步的解说。
#import "RCTViewManager.h"
@interface TestScrollViewManager : RCTViewManager
@end
#import "TestScrollViewManager.h"
#import "TestScrollView.h" //第三方组件的头文件
#import "RCTBridge.h" //进行通信的头文件
#import "RCTEventDispatcher.h" //事件派发,不导入会引起Xcode警告
@interface TestScrollViewManager() <SDCycleScrollViewDelegate>
@end
@implementation TestScrollViewManager
// 标记宏(必要)
RCT_EXPORT_MODULE()
// 事件的导出,onClickBanner对应view中扩展的属性
RCT_EXPORT_VIEW_PROPERTY(onClickBanner, RCTBubblingEventBlock)
// 通过宏RCT_EXPORT_VIEW_PROPERTY完成属性的映射和导出
RCT_EXPORT_VIEW_PROPERTY(autoScrollTimeInterval, CGFloat);
RCT_EXPORT_VIEW_PROPERTY(imageURLStringsGroup, NSArray);
RCT_EXPORT_VIEW_PROPERTY(autoScroll, BOOL);
- (UIView *)view
{
// 实际组件的具体大小位置由js控制
TestScrollView *testScrollView = [TestScrollView cycleScrollViewWithFrame:CGRectZero delegate:self placeholderImage:nil];
// 初始化时将delegate指向了self
testScrollView.pageControlStyle = SDCycleScrollViewPageContolStyleClassic;
testScrollView.pageControlAliment = SDCycleScrollViewPageContolAlimentCenter;
return testScrollView;
}
/**
* 当事件导出用到 sendInputEventWithName 的方式时,会用到
- (NSArray *) customDirectEventTypes {
return @[@"onClickBanner"];
}
*/
#pragma mark SDCycleScrollViewDelegate
/**
* banner点击
*/
- (void)cycleScrollView:(TestScrollView *)cycleScrollView didSelectItemAtIndex:(NSInteger)index
{
// 这也是导出事件的方式,不过好像是旧方法了,会有警告
// [self.bridge.eventDispatcher sendInputEventWithName:@"onClickBanner"
// body:@{@"target": cycleScrollView.reactTag,
// @"value": [NSNumber numberWithInteger:index+1]
// }];
if (!cycleScrollView.onClickBanner) {
return;
}
NSLog(@"oc did click %li", [cycleScrollView.reactTag integerValue]);
// 导出事件
cycleScrollView.onClickBanner(@{@"target": cycleScrollView.reactTag,
@"value": [NSNumber numberWithInteger:index+1]});
}
// 导出枚举常量,给js定义样式用
- (NSDictionary *)constantsToExport
{
return @{
@"SDCycleScrollViewPageContolAliment": @{
@"right": @(SDCycleScrollViewPageContolAlimentRight),
@"center": @(SDCycleScrollViewPageContolAlimentCenter)
}
};
}
// 因为这个类继承RCTViewManager,实现RCTBridgeModule,因此可以使用原生模块所有特性
// 这个方法暂时没用到
RCT_EXPORT_METHOD(testResetTime:(RCTResponseSenderBlock)callback) {
callback(@[@(234)]);
}
@end
RCT_EXPORT_VIEW_PROPERTY(autoScrollTimeInterval, CGFloat);
通过宏RCT_EXPORT_VIEW_PROPERTY完成属性的映射和导出。
CGFloat为autoScrollTimeInterval的OC数据类型,转化成js则对应number。
React Native用RCTConvert来在JavaScript和原生代码之间完成类型转换。
支持的默认转换类型(部分)如下:
如果转换无法完成,会产生一个“红屏”的报错提示,这样你就能立即知道代码中出现了问题。如果一切进展顺利,上面这个宏就已经包含了导出属性的全部实现。
ps:更复杂的类型转换,则涉及到MKCoordinateRegion类型,本文没做应用,具体可参考官方文档例子。
js和原生之间需要有事件的交互,例如,在原生实现的代理或者点击事件,js也需要实时获取到此类事件时,就需要利用事件进行交互。
事件的实现方式有以下两种:
通过sendInputEventWithName实现
1) 实现customDirectEventTypes,返回自定义的事件名数组(on开头才有效)
- (NSArray *) customDirectEventTypes {
return @[@"onClickBanner"];
}
2) sendInputEventWithName实现事件调用(reactTag用于实例的区分)
[self.bridge.eventDispatcher sendInputEventWithName:@"onClickBanner"
body:@{@"target": cycleScrollView.reactTag,
@"value": [NSNumber numberWithInteger:index+1]
}];
通过RCTBubblingEventBlock实现
1) 在封装的View中添加RCTBubblingEventBlock的block属性(on开头才有效)
@property (nonatomic, copy) RCTBubblingEventBlock onClickBanner;
2) 在Manager类中通过宏RCT_EXPORT_VIEW_PROPERTY完成Block属性的映射和导出
RCT_EXPORT_VIEW_PROPERTY(onClickBanner, RCTBubblingEventBlock)
3) 实现事件调用(reactTag用于实例的区分)
cycleScrollView.onClickBanner(@{@"target": cycleScrollView.reactTag,
@"value": [NSNumber numberWithInteger:index+1]});
通过上面两种方式封装好的事件,在js中可以直接利用同名函数调用即可(后面会展示)。
不过关于事件这块,挺多都没完全弄懂,希望有大神引导引导,比如为什么只能定义on开头、如何自定义、如何事件数据源的回调等等。。。
因为我们所有的视图都是UIView的子类,大部分的样式属性应该直接就可以生效。有些属性定义,需要用到枚举,则可以利用通过原生传递来的常数方式来实现,具体实现如下:
// 导出枚举常量,给js定义样式用
- (NSDictionary *)constantsToExport
{
return @{
@"SDCycleScrollViewPageContolAliment": @{
@"right": @(SDCycleScrollViewPageContolAlimentRight),
@"center": @(SDCycleScrollViewPageContolAlimentCenter)
}
};
}
在js中调用则如下:
// 首先获取到常量
var TestScrollViewConsts = require('react-native').UIManager.TestScrollView.Constants;
// 调用
ps: 一部分组件会希望使用自己定义的默认样式,例如UIDatePicker希望自己的大小是固定的。比如大小用原生默认大小,这个例子具体可以参考官方文档的样式模块。
在js中调用,可以有两种方式,一为直接作为扩展React组件调用,二为新建一个组件封装好,再进行调用。
下文用第二种方式,官方推荐,逻辑比较清晰。
1.先倒入原生组件,新建TestScrollView.js文件,在里面对TestScrollView导入,进行属性类型声明等。具体代码和解释如下:
// TestScrollView.js
import React, { Component, PropTypes } from 'react';
import { requireNativeComponent } from 'react-native';
// requireNativeComponent 自动把这个组件提供给 "RCTScrollView"
var RCTScrollView = requireNativeComponent('TestScrollView', TestScrollView);
export default class TestScrollView extends Component {
render() {
return <RCTScrollView {...this.props} />;
}
}
TestScrollView.propTypes = {
/**
* 属性类型,其实不写也可以,js会自动转换类型
*/
autoScrollTimeInterval: PropTypes.number,
imageURLStringsGroup: PropTypes.array,
autoScroll: PropTypes.bool,
onClickBanner: PropTypes.func
};
module.exports = TestScrollView;
2.在index.ios.js中进行调用
var TestScrollView = require('./TestScrollView');
// requireNativeComponent 自动把这个组件提供给 "TestScrollView"
// 如果不新建TestScrollView.js对原生组件封装声明,则直接用这句导入即可
// var TestScrollView = requireNativeComponent('TestScrollView', null);
// 导入常量
var TestScrollViewConsts = require('react-native').UIManager.TestScrollView.Constants;
var bannerImgs = [
'http://upload-images.jianshu.io/upload_images/2321678-ba5bf97ec3462662.png?imageMogr2/auto-orient/strip%7CimageView2/2',
'http://upload-images.jianshu.io/upload_images/1487291-2aec9e634117c24b.jpeg?imageMogr2/auto-orient/strip%7CimageView2/2/w/480/q/100',
'http://f.hiphotos.baidu.com/zhidao/pic/item/e7cd7b899e510fb37a4f2df3db33c895d1430c7b.jpg'
];
class NativeUIModule extends Component {
constructor(props){
super(props);
this.state={
bannerNum:0
}
}
render() {
return (
<ScrollView style = {{marginTop:64}}>
<View>
<TestScrollView style={styles.container}
autoScrollTimeInterval = {2}
imageURLStringsGroup = {bannerImgs}
pageControlAliment = {TestScrollViewConsts.SDCycleScrollViewPageContolAliment.right}
onClickBanner={(e) => {
console.log('test' + e.nativeEvent.value);
this.setState({bannerNum:e.nativeEvent.value});
}}
/>
<Text style={{fontSize: 15, margin: 10, textAlign:'center'}}>
点击banner -> {this.state.bannerNum}
Text>
View>
ScrollView>
);
}
}
// 实际组件的具体大小位置由js控制
const styles = StyleSheet.create({
container:{
padding:30,
borderColor:'#e7e7e7',
marginTop:10,
height:200,
},
});
AppRegistry.registerComponent('NativeTest2', () => NativeUIModule);
若使用第一种方式,即使用下面语句进行组件的引用:
var TestScrollView = requireNativeComponent('TestScrollView', null);
则会存在的这样的问题:
虽然很方便简单,但这样并不能很好的说明这个组件的用法——用户要想知道我们的组件有哪些属性可以用,以及可以取什么样的值,他不得不一路翻到Objective-C的代码。要解决这个问题,我们可以创建一个封装组件,并且通过PropTypes来说明这个组件的接口。
注意:我们现在把requireNativeComponent的第二个参数从null变成了用于封装的组件TestScrollView。这使得React Native的底层框架可以检查原生属性和包装类的属性是否一致,来减少出现问题的可能。
关于属性、事件的调用,则是如下直接调用:
2}
imageURLStringsGroup = {bannerImgs}
pageControlAliment = {TestScrollViewConsts.SDCycleScrollViewPageContolAliment.right}
onClickBanner={(e) => {
console.log('test' + e.nativeEvent.value);
this.setState({bannerNum:e.nativeEvent.value});
}}
/>
关于事件,需要注意的是,事件事件默认传递的是字典数据类型,即json,在js中调用需要利用e.nativeEvent才能将字典取出,在具体调用里面的值。(这里也还未研究透彻、需要指导)
React Native 与原生代码之间混合互相调用。经典项目如下:
链接: https://pan.baidu.com/s/1kVwRnYB 密码: vuwz