适用于 iOS + Android 的 React Native 地图组件
该项目由一小群人维护,任何有关问题和拉取请求的帮助都将受到赞赏。如果您有能力并且愿意做出贡献,请阅读指南。
请参阅安装说明。
请参阅所包含示例项目的设置说明。
react-native >= 0.74
。react-native >= 0.64.3
。 <MapView />
组件API
<Marker />
组件API
<Callout />
组件API
<Polygon />
组件 API
<Polyline />
组件API
<Circle />
组件API
<Overlay />
组件API
<Heatmap />
组件API
<Geojson />
组件API
import MapView from 'react-native-maps' ;
或者
var MapView = require ( 'react-native-maps' ) ;
构建此 MapView 组件是为了将地图上的要素(例如标记、多边形等)指定为 MapView 本身的子级。这提供了一个直观且类似反应的 API,用于以声明方式控制地图上的功能。
< MapView
initialRegion = { {
latitude : 37.78825 ,
longitude : - 122.4324 ,
latitudeDelta : 0.0922 ,
longitudeDelta : 0.0421 ,
} }
/ >
getInitialState ( ) {
return {
region : {
latitude : 37.78825 ,
longitude : - 122.4324 ,
latitudeDelta : 0.0922 ,
longitudeDelta : 0.0421 ,
} ,
} ;
}
onRegionChange ( region ) {
this . setState ( { region } ) ;
}
render ( ) {
return (
< MapView
region = { this . state . region }
onRegionChange = { this . onRegionChange }
/ >
) ;
}
import { Marker } from 'react-native-maps' ;
< MapView region = { this . state . region } onRegionChange = { this . onRegionChange } >
{ this . state . markers . map ( ( marker , index ) => (
< Marker
key = { index }
coordinate = { marker . latlng }
title = { marker . title }
description = { marker . description }
/ >
) ) }
< / MapView > ;
png
图像(我们称之为custom_pin
) - 有关更多信息,请访问 Android、iOS < Marker
coordinate = { { latitude : latitude , longitude : longitude } }
image = { { uri : 'custom_pin' } }
/ >
注意:您还可以传递图像二进制数据,例如image={require('custom_pin.png')}
,但这不会随着不同的屏幕尺寸而很好地缩放。
注意:这会对性能产生影响,如果您希望使用更简单的解决方案,请使用自定义图像(省去您自己的麻烦)
< Marker coordinate = { { latitude : latitude , longitude : longitude } } >
< MyCustomMarkerView { ... marker } / >
< / Marker >
import { Callout } from 'react-native-maps' ;
< Marker coordinate = { marker . latlng } >
< MyCustomMarkerView { ... marker } / >
< Callout >
< MyCustomCalloutView { ... marker } / >
< / Callout >
< / Marker > ;
< MapView initialRegion = { ... } >
< Marker draggable
coordinate = { this . state . x }
onDragEnd = { ( e ) => this . setState ( { x : e . nativeEvent . coordinate } ) }
/ >
< / MapView >
import { UrlTile } from 'react-native-maps' ;
< MapView region = { this . state . region } onRegionChange = { this . onRegionChange } >
< UrlTile
/**
* The url template of the tile server. The patterns {x} {y} {z} will be replaced at runtime
* For example, http://c.tile.openstreetmap.org/{z}/{x}/{y}.png
*/
urlTemplate = { this . state . urlTemplate }
/**
* The maximum zoom level for this tile overlay. Corresponds to the maximumZ setting in
* MKTileOverlay. iOS only.
*/
maximumZ = { 19 }
/**
* flipY allows tiles with inverted y coordinates (origin at bottom left of map)
* to be used. Its default value is false.
*/
flipY = { false }
/ >
< / MapView > ;
对于 Android:在 AndroidManifest.xml 中添加以下行
< uses-permission android : name = " android.permission.INTERNET " />
对于 IOS:在您的应用程序中配置应用程序传输安全性
该库使用新的渲染器互操作层与 Fabric 配合使用
有一条警告消息表明这些步骤不是必需的;但到目前为止,如果没有它们,我们就无法让示例正常工作。
打开配置文件:在项目目录中找到react-native-config
文件。
添加以下配置:包括 Android 和 iOS 平台的unstable_reactLegacyComponentNames
数组,如下所示:
module . exports = {
project : {
android : {
unstable_reactLegacyComponentNames : [
'AIRMap' ,
'AIRMapCallout' ,
'AIRMapCalloutSubview' ,
'AIRMapCircle' ,
'AIRMapHeatmap' ,
'AIRMapLocalTile' ,
'AIRMapMarker' ,
'AIRMapOverlay' ,
'AIRMapPolygon' ,
'AIRMapPolyline' ,
'AIRMapUrlTile' ,
'AIRMapWMSTile' ,
] ,
} ,
ios : {
unstable_reactLegacyComponentNames : [
'AIRMap' ,
'AIRMapCallout' ,
'AIRMapCalloutSubview' ,
'AIRMapCircle' ,
'AIRMapHeatmap' ,
'AIRMapLocalTile' ,
'AIRMapMarker' ,
'AIRMapOverlay' ,
'AIRMapPolygon' ,
'AIRMapPolyline' ,
'AIRMapUrlTile' ,
'AIRMapWMSTile' ,
] ,
} ,
} ,
} ;
查看示例项目以查看其实际情况。
切片可以使用 xyz 切片方案本地存储在设备内,也可以显示为切片叠加。当图块可用于设备存储中的选定地图区域时,这对于离线地图使用尤其有用。
import { LocalTile } from 'react-native-maps' ;
< MapView region = { this . state . region } onRegionChange = { this . onRegionChange } >
< LocalTile
/**
* The path template of the locally stored tiles. The patterns {x} {y} {z} will be replaced at runtime
* For example, /storage/emulated/0/mytiles/{z}/{x}/{y}.png
*/
pathTemplate = { this . state . pathTemplate }
/**
* The size of provided local tiles (usually 256 or 512).
*/
tileSize = { 256 }
/ >
< / MapView > ;
对于 Android:LocalTile 仍然只是覆盖在原始地图图块上。这意味着如果设备在线,仍然会下载底层图块。如果不需要下载/显示原始图块,请将 mapType 设置为“none”。例如:
<MapView
mapType={Platform.OS == "android" ? "none" : "standard"}
>
请参阅 OSM Wiki 了解如何下载切片以供离线使用。
将您想要覆盖MapView
的组件放置在MapView
结束标记下方。绝对定位这些元素。
render ( ) {
return (
< MapView
region = { this . state . region }
/ >
< OverlayComponent
style = { { position : "absolute" , bottom : 50 } }
/ >
) ;
}
<MapView provider="google" googleMapId="yourStyledMapId" />
iOS 和 Android 上的 Google 地图支持通过 google 云平台进行样式设置,样式化的地图在 googleMapId 下发布,只需将属性 googleMapId 设置为 MapView 即可使用样式地图更多信息在这里:google 地图 id
<MapView />
组件及其子组件有多个可以订阅的事件。此示例在日志中显示其中一些内容作为演示。
人们可以使用 refs 和组件方法,或者通过传入更新的region
属性来更改地图视图的位置。组件方法将允许我们像原生 API 一样将动画移动到给定位置。
<MapView />
组件可以与 Animated API 一起使用,将整个region
属性声明为动画值。这允许人们对 MapView 的缩放和位置以及其他手势进行动画处理,给人一种很好的感觉。
此外,标记视图可以使用动画 API 来增强效果。
问题:由于 Android 需要将其标记视图渲染为位图,因此动画 API 可能与标记视图不兼容。不确定这是否可以解决。
标记的坐标也可以设置动画,如下例所示:
到目前为止, <Circle />
、 <Polygon />
和<Polyline />
可以作为子组件传递给<MapView />
组件。
可以使用<Polyline>
组件的strokeColors
属性创建渐变多段线。
除非指定自定义标记,否则将呈现默认标记。人们可以选择使用pinColor
属性来调整默认标记的颜色。
对标记的标注可以是完全任意的反应视图,类似于标记。因此,它们可以像任何其他视图一样进行交互。
此外,您可以通过<Marker />
的title
和description
属性退回到仅具有标题/描述的标准行为。
自定义标注视图可以是整个工具提示气泡,也可以只是系统默认气泡内的内容。
要处理标注特定子视图上的按下,请使用<CalloutSubview />
和onPress
。请参阅Callouts.js
示例。
可以仅使用图像来自定义标记,并使用image
属性指定。
标记是可拖动的,并发出连续的拖动事件以在拖动期间更新其他 UI。
使用liteMode
prop 在 Android 上启用精简模式。当 View 或 ScrollView 中有多个地图时是理想的选择。
Poi 是可点击的,您可以捕获事件以获取其信息(通常使用 placeId 从 Google Place 获取完整详细信息)。
MapView 可以接受AnimatedRegion
值作为其region
属性。这允许您利用动画 API 来控制地图的中心和缩放。
import MapView , { AnimatedRegion , Animated } from 'react-native-maps' ;
getInitialState ( ) {
return {
region : new AnimatedRegion ( {
latitude : LATITUDE ,
longitude : LONGITUDE ,
latitudeDelta : LATITUDE_DELTA ,
longitudeDelta : LONGITUDE_DELTA ,
} ) ,
} ;
}
onRegionChange ( region ) {
this . state . region . setValue ( region ) ;
}
render ( ) {
return (
< Animated
region = { this . state . region }
onRegionChange = { this . onRegionChange }
/ >
) ;
}
标记还可以接受AnimatedRegion
值作为坐标。
import MapView , { AnimatedRegion , MarkerAnimated } from 'react-native-maps' ;
getInitialState ( ) {
return {
coordinate : new AnimatedRegion ( {
latitude : LATITUDE ,
longitude : LONGITUDE ,
} ) ,
} ;
}
componentWillReceiveProps ( nextProps ) {
const duration = 500
if ( this . props . coordinate !== nextProps . coordinate ) {
if ( Platform . OS === 'android' ) {
if ( this . marker ) {
this . marker . animateMarkerToCoordinate (
nextProps . coordinate ,
duration
) ;
}
} else {
this . state . coordinate . timing ( {
... nextProps . coordinate ,
useNativeDriver : true , // defaults to false if not passed explicitly
duration
} ) . start ( ) ;
}
}
}
render ( ) {
return (
< MapView initialRegion = { ... } >
< MarkerAnimated
ref = { marker => { this . marker = marker } }
coordinate = { this . state . coordinate }
/ >
< / MapView >
) ;
}
import MapView , { Marker } from 'react-native-maps' ;
getInitialState ( ) {
return {
coordinate : {
latitude : LATITUDE ,
longitude : LONGITUDE ,
} ,
} ;
}
takeSnapshot ( ) {
// 'takeSnapshot' takes a config object with the
// following options
const snapshot = this . map . takeSnapshot ( {
width : 300 , // optional, when omitted the view-width is used
height : 300 , // optional, when omitted the view-height is used
region : { . . } , // iOS only, optional region to render
format : 'png' , // image formats: 'png', 'jpg' (default: 'png')
quality : 0.8 , // image quality: 0..1 (only relevant for jpg, default: 1)
result : 'file' // result types: 'file', 'base64' (default: 'file')
} ) ;
snapshot . then ( ( uri ) => {
this . setState ( { mapSnapshot : uri } ) ;
} ) ;
}
render ( ) {
return (
< View >
< MapView initialRegion = { ... } ref = { map => { this . map = map } } >
< Marker coordinate = { this . state . coordinate } / >
< / MapView >
< Image source = { { uri : this . state . mapSnapshot . uri } } / >
< TouchableOpacity onPress = { this . takeSnapshot } >
Take Snapshot
< / TouchableOpacity >
< / View >
) ;
}
传递一组标记标识符以使地图重新聚焦。
传递坐标数组以将地图区域聚焦在所述坐标上。
const styles = StyleSheet . create ( {
map : {
... StyleSheet . absoluteFillObject ,
} ,
} ) ;
< MapView
style = { styles . map }
// other props
/ >
坏的:
< View >
< TextInput / >
< MapView / >
< / View >
好的:
< View >
< MapView / >
< TextInput / >
< / View >
由于 MapView 独特的渲染方法,未由该库声明的组件(例如:标记、折线)不得成为 MapView 组件的子组件。让您的自定义组件/视图位于 MapView 组件之外并绝对定位,以确保它们仅根据需要重新渲染。示例: 坏:
< View style = { StyleSheet . absoluteFillObject } >
< MapView style = { StyleSheet . absoluteFillObject } >
< View style = { { position : 'absolute' , top : 100 , left : 50 } } / >
< / MapView >
< / View >
好的:
< View style = { StyleSheet . absoluteFillObject } >
< MapView style = { StyleSheet . absoluteFillObject } / >
< View style = { { position : 'absolute' , top : 100 , left : 50 } } / >
< / View >
来源:#1901
当您将应用程序后台运行或切换到另一个应用程序时, <MapView>
在mapType: "standard"
中使用 Apple 地图有时会崩溃。这只是使用 Metal API 验证的 XCode 中的一个问题,在生产中不会发生。要在 XCode 中调试时消除此问题,请转至Edit Scheme... -> Run (Debug) -> Diagnostics
并取消选中Metal -> API Validation
。 (h/t @Simon-TechForm)。
来源:#3957(评论)
如果无限调用onRegionChangeComplete
中的状态更改,请添加一个条件以限制这些调用仅在由于用户操作而发生区域更改时发生。
onRegionChangeComplete = { ( region , gesture ) => {
// This fix only works on Google Maps because isGesture is NOT available on Apple Maps
if ( ! gesture . isGesture ) {
return ;
}
// You can use
dispatch ( { type : "map_region" , payload : { mapRegion : region }