快速上手React Native 和 原生UI 組件通訊

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 測試這個文件就是)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容