在开发React Native的App的时候,你会遇到很多情况是原生的视图组件已经开发好了的。有的是系统的SDK提供的,有的是第三方试图组件,总之你的APP可以直接使用的原生视图是很多的。React Native提供了一套完善的机制,你可以非常简单的用来包装已有的原生视图。

代码地址:https://github.com/future-challenger/react-native-gaode-map

下面就用高德地图作为例子讲解如何包装原生视图。高德地图本身不仅有视图需要展示,还有一些和React Native交互的部分。比如给Js代码发送事件,接受Js发送的方法调用等。

简单实现

基本山只需要三步就可以达到目的:

  1. 创建RCTViewManager的子类
  2. 在源文件里添加RCT_EXPORT_MODULE()宏的调用
  3. 实现- (UIView *)view方法

看看代码:

//.h
#import <Foundation/Foundation.h>
#import <React/RCTViewManager.h> @interface GDMapViewManager : RCTViewManager @end //.m
#import "GDMapViewManager.h"
#import "GDMapView.h"
#import <MAMapKit/MAMapKit.h>
#import <AMapFoundationKit/AMapFoundationKit.h> @implementation GDMapViewManager RCT_EXPORT_MODULE() - (UIView *)view {
MAMapView *mapView = [[MAMapView alloc] init];
mapView.showsUserLocation = YES; // 显示用户位置蓝点
mapView.userTrackingMode = MAUserTrackingModeFollow; return mapView;
} @end // index.ios.js
// import from `react` & `react native`... import { requireNativeComponent } from 'react-native' const GDMapView = requireNativeComponent('GDMapView', null) export default class mobike extends Component {
render() {
return (
<View style={styles.container}>
<GDMapView style={{ flex: 1, }} />
</View>
);
}
} // styles...

属性

要导出属性:

RCT_EXPORT_VIEW_PROPERTY(showsCompass, BOOL)

这里导出的属性是高德地图的内置属性,表示是否在地图上显示指南针。可以如此使用:

<GDMapView style={{ flex: 1, }} showsCompass={true} />

如果是我们自定义的属性,而不是高德地图内置的属性该如何导出呢?来看一个例子:

RCT_CUSTOM_VIEW_PROPERTY(center, CLLocationCoordinate2D, GDMapView) {
[view setCenterCoordinate:json ? [RCTConvert CLLocationCoordinate2D:json] : defaultView.centerCoordinate];
}

写这个属性是因为出过来的参数是json串,只有最初是的类型NSStringint之类的可用,其他类型的都需要转化。比如这里要用的CLLocationCoordinate2D这个类型。所以我们需要判断js传过来的json是否为空,并在不为空的时候转化成CLLocationCoordinate2D对象。如果js传过来的json为空的话则使用defaultView.centerCoordinate来填充。

处理用户发出的事件

处理直接或者间接的从用户发出的事件。比如,用户对地图的各种操作都会生成对应的事件需要原生代码来处理。

要实现这部分功能基本只需要两步:

  1. 在视图部分添加一个属性:@property (nonatomic, copy) RCTBubblingEventBlock onChange;
  2. 在视图Manager部分暴露出这个属性:RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)

之后在相对应的地方调用就可以了,如:

- (void)mapView:(GDMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
if (!mapView.onChange) {
return;
} MACoordinateRegion region = mapView.region;
mapView.onChange(@{
@"region": @{
@"latitude": @(region.center.latitude),
@"longitude": @(region.center.longitude),
@"latitudeDelta": @(region.span.latitudeDelta),
@"longitudeDelta": @(region.span.longitudeDelta),
}
});
}

建立对应的Js组件

上文的方式使用原生组件会显得凌乱,不易控制。最好的方式就是建立一个对应的Js组件。

import React from 'react';
import {
requireNativeComponent
} from 'react-native'; export default class MapView extends React.Component {
constructor(props) {
super(props)
} render() {
return (
<GDMapView {...this.props} />
)
}
} MapView.propTypes = {
marker: React.PropTypes.object,
markers: React.PropTypes.array,
zoom: React.PropTypes.number,
centerCoordinate: React.PropTypes.object,
showScale: React.PropTypes.bool,
showsCompass: React.PropTypes.bool,
}; var GDMapView = requireNativeComponent('GDMapView', MapView);

之后就可以这样使用了:

<MapView
style={{ flex: 1, marginTop: 20, }}
marker={marker} showsCompass={false}
markers={markers}
zoom={10}
centerCoordinate={{ latitude: 39.909520, longitude: 116.336170 }}
showScale={false} />

注意,给Js组件定义PropTypes是必须的。而且我这里的定义还是有点模糊。官网的比较细致,列在这里:

MapView.propTypes = {
region: React.PropTypes.shape({
/**
* Coordinates for the center of the map.
*/
latitude: React.PropTypes.number.isRequired,
longitude: React.PropTypes.number.isRequired, /**
* Distance between the minimum and the maximum latitude/longitude
* to be displayed.
*/
latitudeDelta: React.PropTypes.number.isRequired,
longitudeDelta: React.PropTypes.number.isRequired,
}),
};

官网的例子对region这prop定义的相当的细致,不是一个`React.PropTypes.object就过去了的。

还有一些属性,你不想它们作为对应Js组件的API的一部分。所以,需要隐藏起来。那么你可以在绑定原生组件和Js组件的时候指定它们不作为API的一部分。如:

const GDMapView = requireNativeComponent('GDMapView', MapView, {
nativeOnly: { onChange: true }
});

在对应的组件里处理事件

  1. 在本组件内绑定原生组件的onChange事件,如这里的_onChange()方法。
  2. 在绑定好的方法里(如_onChange()方法内)调用外部传入的事件处理方法(如this.props.onRegionChange

当然,你不会忘了给this.props.onRegionChangePropTypes的。

export default class MapView extends React.Component {
constructor(props) {
super(props) this._onChange = this._onChange.bind(this);
} _onChange(event) {
if(!this.props.onRegionChange) {
return;
} this.props.onRegionChange(event.NativeEvent.region)
} render() {
return (
<GDMapView {...this.props} onChange={this._onChange} />
)
}
} MapView.propTypes = {
//...
onRegionChange: React.PropTypes.func,
}; const GDMapView = requireNativeComponent('GDMapView', MapView, {
nativeOnly: { onChange: true }
});

填坑完毕

到这里你可以在React Natie里愉快的使用原生组件了。

后面我们来探讨一下在Android里如何处理这些问题。

React Native填坑之旅 -- 使用iOS原生视图(高德地图)的更多相关文章

  1. React Native填坑之旅--与Native通信之iOS篇

    终于开始新一篇的填坑之旅了.RN厉害的一个地方就是RN可以和Native组件通信.这个Native组件包括native的库和自定义视图,我们今天主要设计的内容是native库方面的只是.自定义视图的使 ...

  2. React Native填坑之旅--Flow篇(番外)

    flow不是React Native必会的技能,但是作为正式的产品开发优势很有必要掌握的技能之一.所以,算是RN填坑之旅系列的番外篇. Flow是一个静态的检查类型检查工具,设计之初的目的就是为了可以 ...

  3. React Native填坑之旅--布局篇

    代码在这里: https://github.com/future-challenger/petshop/tree/master/client/petshop/src/controller 回头看看RN ...

  4. React Native填坑之旅--组件生命周期

    这次我们来填React Native生命周期的坑.这一点非常重要,需要有一个清晰的认识.如果你了解Android或者iOS的话,你会非常熟悉我们今天要说的的内容. 基本上一个React Native的 ...

  5. React Native填坑之旅--重新认识RN

    如同黑夜里的一道光一样,就这么知道了F8. F8是每年一次Facebook每年一次的开发者大会.每次大会都会release相应的APP,iOS.Android都有.之前都是用Native开发的,但是2 ...

  6. React Native填坑之旅--Navigation篇

    React Native的导航有两种,一种是iOS和Android通用的叫做Navigator,一种是支持iOS的叫做NavigatorIOS.我们这里只讨论通用的Navigator.会了Naviga ...

  7. React Native填坑之旅--ListView篇

    列表显示数据,基本什么应用都是必须.今天就来从浅到深的看看React Native的ListView怎么使用.笔者写作的时候RN版本是0.34. 最简单的 //@flow import React f ...

  8. React Native填坑之旅--动画

    动画是提高用户体验不可缺少的一个元素.恰如其分的动画可以让用户更明确的感知当前的操作是什么. 无疑在使用React Native开发应用的时候也需要动画.这就需要知道RN都给我们提供了那些动画,和每个 ...

  9. React Native填坑之旅--Button篇

    从React过来,发现React Native(以下简称RN)居然没有Button.隔壁的iOS是有UIButton的,隔壁的隔壁的Android里也是有的.没有Button,就没有点击效果啊.这还真 ...

随机推荐

  1. Spring基本使用方法_Bean对象

    Spring基本使用方法_Bean对象 Struts与Hibernate可以做什么事? Struts MVC中控制层解决方案.可以进行请求数据自动封装,类型转换,文件上传,效验..... Hibern ...

  2. python 爬照片 模拟浏览器 先登录账号

    # -*- coding: utf-8 -*-"""Created on Mon Mar 7 10:53:40 2016 @author: root"" ...

  3. JAVA WEB 中的编码分析

    JAVA WEB 中的编码分析 */--> pre.src {background-color: #292b2e; color: #b2b2b2;} pre.src {background-co ...

  4. 关于老版本ubuntu源不能用的问题

    在解决方向键为大写ABCD时安装vim 我的是Ubuntu 10.10 老版本 输入 sudo apt-get install vim 时出现 Package 'vim' has no install ...

  5. jQuery中animate动画第二次点击事件没反应

    jQuery中animate动画第二次点击事件没反应 用animate做点击翻页动画时发现第二次点击事件动画没反应,而第一次点击有动画效果,代码如下: 复制代码 代码如下: $(".page ...

  6. MariaDB10自动化安装部署

    去MariaDB官网下载MariaDB本文用的是MariaDB 10.1.16 https://downloads.mariadb.org 选择二进制版本,下载到/root目录下 mariadb-10 ...

  7. JVM 参数设置

    YGC FGC 都会影响程序的运行,中断程序,JVM参数调整比较复杂,现在记录了一下平时常用的JVM参数: jar 包启动: usr/java/bin/java -jar -Xms2560m -Xmx ...

  8. 选项卡(TabHost)的功能与用法

    TabHost是一种非常实用的组件,TabHost可以很方便地在窗口上放置多个便签页,每个标签页相当于获得了一个与外部容器相同大小的组件摆法区域.通过这种方式,就可以在一个容器里放置更多组件,例如手机 ...

  9. 如何在Visio 2007中画接口和实现类的关系图

    http://blog.sina.com.cn/s/blog_53fc9db50100as5o.html 在Visio图形元素上,点击右键,选择“形状显示选项”,将“实现链接”选中,这个时候,类图形元 ...

  10. Redis key 相关命令

    其实本质上,Redis 就是一个Key---Value 数据库.这里我先介绍下Redis中关于的key的相关命令, 注意:key是字符串存储,但是不能使用 空格 或者 “\n”,value 则可以使用 ...