快速上手React Native 和 原生UI 组件通讯

1.使用场景

使用在react native 页面需要调用原生 组件或原生三方的时候,如:

(1) 在react native 的页面里的一个区域 显示原生地图(因为RN 的地图插件好多功能没有)

(2)在react native 的 显示原生微信(因为RN 的微信插件响应比较慢,用户体验不好)

2. 案例讲解

需求:在RN 页面添加原生组件

原理分析:

Native 视图是通过 RCTViewManager 的子类创建和操做的。这些子类的功能与视图控制器很相似,但本质上它们是单件模式——桥只为每一个子类创建一个实例

发送视图基本步簇:

1.创建基本的子类。

2.添加标记宏 RCT_EXPORT_MODULE()。

3.实现 -(UIView *)view 方法。

4. 已有属性设置RCT_EXPORT_VIEW_PROPERTY(参数名,参数类型);

5.自定义属性设置 RCT_CUSTOM_VIEW_PROPERTY(name, type, viewClass) 

示例代码:

//  RCTMapManager.h 

#import <React/RCTViewManager.h> 

@interface RCTMapManager : RCTViewManager   

@end

//  RCTMapManager.m

#import "RCTMapManager.h"

#import <MapKit/MapKit.h>

#import "RCTConvert+Category.h"

@implementation RCTMapManager

RCT_EXPORT_MODULE()

- (UIView *)view{ 

 MKMapView *map = [[MKMapView alloc] init]; 

 return map;

}

RCT_EXPORT_VIEW_PROPERTY(zoomEnabled, BOOL);  //MKMapView 自带属性

//添加自定义属性来设置地图的区域

RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, MKMapView){

  [view setRegion:json ? [RCTConvert MKCoordinateRegion:json] : defaultView.region animated:YES];

}

@end

添加RCTConvert+Category 进行json 转CLLocationCoordinate2D

//RCTConvert+Category.h

#import<React/RCTConvert.h>

#import<MapKit/MapKit.h>

@interface RCTConvert (Category)

+ (MKCoordinateRegion)MKCoordinateRegion:(id)json; 

@end

//RCTConvert+Category.m

#import "RCTConvert+Category.h"

@implementation RCTConvert (Category)

RCT_CONVERTER(CLLocationDegrees, CLLocationDegrees, doubleValue);RCT_CONVERTER(CLLocationDistance, CLLocationDistance, doubleValue);

+ (CLLocationCoordinate2D)CLLocationCoordinate2D:(id)json{ 

json = [self NSDictionary:json]; 

return (CLLocationCoordinate2D){   [self CLLocationDegrees:json[@"latitude"]],    [self CLLocationDegrees:json[@"longitude"]] };

}

+ (MKCoordinateSpan)MKCoordinateSpan:(id)json{

  json = [self NSDictionary:json];

  return (MKCoordinateSpan){   [self CLLocationDegrees:json[@"latitudeDelta"]],   [self CLLocationDegrees:json[@"longitudeDelta"]]  };

}

+ (MKCoordinateRegion)MKCoordinateRegion:(id)json{ 

return (MKCoordinateRegion){    [self CLLocationCoordinate2D:json],   [self MKCoordinateSpan:json]  };

}

@end

ok! OC中的代码好了 开始 RN 中的吧

//testMap.js 中的代码

import React, {Component} from 'react';

import { View,requireNativeComponent} from 'react-native';

var RCTMap = requireNativeComponent('RCTMap', null);

export default class testMap extends Component{

render(){

     var region = { latitude: 30.60, longitude: 114.30, latitudeDelta: 0.1, longitudeDelta: 0.1, };            

   return( 

      <View style = {{flex:1}}>

                <RCTMap style={{flex:1}} zoomEnabled={true} region={region}/>

      </View>

     )

   }

}

//index.js 中的代码

import {AppRegistry} from 'react-native';

import {name as appName} from './app.json';

import MapView from './src/testMap';

AppRegistry.registerComponent(appName, () => MapView);

6.UI组件事件回调,思路是把响应事件作为参数传入

使用的还是 RCT_EXPORT_VIEW_PROPERTY(参数名,参数类型);   但此时出参数类型是RCTBubblingEventBlock,参数名是方法名,不可以直接在上面的代码RCTMapManager.m 中加,不报错找不到传入的方法,因为此时添加的事件一般是自定义的,MKMapView没有该方法。

顺便将上面的代码整理一下,来一份新的代码吧,全部代码如下:

//RNTMapManager.h

#import <React/RCTViewManager.h>

@interface RNTMapManager : RCTViewManager

@end

//#import "RNTMapManager.m"

#import "RNTMapManager.h"

#import "RNTMapView.h"

#import "RCTConvert+Category.h" //带入上面的分类

@interface RNTMapManager()

@end

@implementation RNTMapManager

RCT_EXPORT_MODULE()

RCT_EXPORT_VIEW_PROPERTY(zoomEnabled, BOOL)

RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, MKMapView){

   [view setRegion:json ? [RCTConvert MKCoordinateRegion:json] : defaultView.region animated:YES];

}

RCT_EXPORT_VIEW_PROPERTY(onRegionChange, RCTBubblingEventBlock)

- (UIView *)view{ 

RNTMapView *map = [[RNTMapView alloc]init]; 

map.delegate = self; 

return map;

}

#pragma mark MKMapViewDelegate

- (void)mapView:(RNTMapView *)mapView regionDidChangeAnimated:(BOOL)animated{ 

  if (!mapView.onRegionChange){    return;   }    

  MKCoordinateRegion region = mapView.region; 

  mapView.onRegionChange(@{  @"region": @{  

       @"latitude": @(region.center.latitude),                              

       @"longitude": @(region.center.longitude),  

       @"latitudeDelta": @(region.span.latitudeDelta),                            

       @"longitudeDelta": @(region.span.longitudeDelta),                              

      }                          

  });

}

@end

MKMapView 文件代码

#import<MapKit/MapKit.h>

#import<React/RCTComponent.h>

@interface RNTMapView : MKMapView

@property (nonatomic, copy) RCTBubblingEventBlock onRegionChange; //用属性保存事件

@end

#import "RNTMapView.h"

@implementation RNTMapView

@end

MapView.js 中的代码

import PropTypes from "prop-types";

import React from "react";

import { requireNativeComponent } from "react-native";

class MapView extends React.Component {

       _onRegionChange = (event) => {

              if (!this.props.onRegionChange) {    return;   }

             this.props.onRegionChange(event.nativeEvent);

       }

       render() {

             return< RNTMap {...this.props}   onRegionChange={this._onRegionChange} /> ;

       }

}

MapView.propTypes = {

     /** * A Boolean value that determines whether the user may use pinch * gestures to zoom    in and out of the map. */

     zoomEnabled: PropTypes.bool,

     /** * 地图要显示的区域。 * * 区域由中心点坐标和区域范围坐标来定义。 * */

    region: PropTypes.shape({  

     /** * 地图中心点的坐标。 */

          latitude: PropTypes.number.isRequired,

          longitude: PropTypes.number.isRequired, /** * 最小/最大经、纬度间的距离。 * */

          latitudeDelta: PropTypes.number.isRequired,

          longitudeDelta: PropTypes.number.isRequired,

    }),

    onRegionChange: PropTypes.func,

};

var RNTMap = requireNativeComponent("RNTMap", MapView);

export default MapView;

app.js

import React, {Component} from 'react';

import { View} from 'react-native';

import MapView from './src/MapView'

export default class App extends Component {

  onRegionChange(event) {

        alert("地图移动弹出这个消息")

  }

  render() {

   var region = { latitude: 30.60, longitude: 114.30, latitudeDelta: 0.1, longitudeDelta: 0.1, };    

   return ( <MapView

                 region={region}

                 zoomEnabled={false}

                 style={{ flex: 1 }}

                 onRegionChange={this.onRegionChange}

               />  );

    }

}

index.js

import {AppRegistry} from 'react-native';

import App from './App';

import {name as appName} from './app.json';

AppRegistry.registerComponent(appName, () => App);

当移动地图的时候发现可以 弹出react native 代码的提示框了

可以参考:  dome 源码(redux 测试这个文件就是)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容