React Native开发React Native开发经验集React Native开发技巧

React Native 和 原生UI 组件通讯

2018-08-08  本文已影响20人  欧辰_OSR

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 测试这个文件就是)

上一篇 下一篇

猜你喜欢

热点阅读