1.使用場景
使用在react native 頁面需要調(diào)用原生 組件或原生三方的時候,如:
(1) 在react native 的頁面里的一個區(qū)域 顯示原生地圖(因為RN 的地圖插件好多功能沒有)
(2)在react native 的 顯示原生微信(因為RN 的微信插件響應(yīng)比較慢,用戶體驗不好)
2. 案例講解
需求:在RN 頁面添加原生組件
原理分析:
Native 視圖是通過?RCTViewManager?的子類創(chuàng)建和操做的。這些子類的功能與視圖控制器很相似,但本質(zhì)上它們是單件模式——橋只為每一個子類創(chuàng)建一個實例
發(fā)送視圖基本步簇:
1.創(chuàng)建基本的子類。
2.添加標(biāo)記宏?RCT_EXPORT_MODULE()。
3.實現(xiàn)?-(UIView *)view?方法。
4. 已有屬性設(shè)置RCT_EXPORT_VIEW_PROPERTY(參數(shù)名,參數(shù)類型);
5.自定義屬性設(shè)置?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 自帶屬性
//添加自定義屬性來設(shè)置地圖的區(qū)域
RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, MKMapView){
? [view setRegion:json ? [RCTConvert MKCoordinateRegion:json] : defaultView.region animated:YES];
}
@end
添加RCTConvert+Category 進(jìn)行json 轉(zhuǎn)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組件事件回調(diào),思路是把響應(yīng)事件作為參數(shù)傳入
使用的還是?RCT_EXPORT_VIEW_PROPERTY(參數(shù)名,參數(shù)類型); ? 但此時出參數(shù)類型是RCTBubblingEventBlock,參數(shù)名是方法名,不可以直接在上面的代碼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,
? ? ?/** * 地圖要顯示的區(qū)域。 * * 區(qū)域由中心點坐標(biāo)和區(qū)域范圍坐標(biāo)來定義。 * */
? ? region: PropTypes.shape({ ?
? ? ?/** * 地圖中心點的坐標(biāo)。 */
? ? ? ? ? latitude: PropTypes.number.isRequired,
? ? ? ? ? longitude: PropTypes.number.isRequired, /** * 最小/最大經(jīng)、緯度間的距離。 * */
? ? ? ? ? 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);
當(dāng)移動地圖的時候發(fā)現(xiàn)可以 彈出react native 代碼的提示框了
可以參考: ?dome 源碼(redux 測試這個文件就是)