適用於 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 }