Componentes de React Native Map para iOS + Android
Este proyecto lo mantiene un pequeño grupo de personas y siempre se agradece cualquier ayuda con problemas y solicitudes de extracción. Si puede y desea contribuir, lea las pautas.
Consulte las instrucciones de instalación.
Consulte las instrucciones de configuración para el proyecto de ejemplo incluido.
react-native >= 0.74
.react-native >= 0.64.3
. API de componente <MapView />
<Marker />
API de componente
<Callout />
API de componente
API de componente <Polygon />
API de componente <Polyline />
<Circle />
API de componente
<Overlay />
API de componente
<Heatmap />
API de componentes
<Geojson />
API de componentes
import MapView from 'react-native-maps' ;
o
var MapView = require ( 'react-native-maps' ) ;
Este componente MapView está diseñado para que las características del mapa (como marcadores, polígonos, etc.) se especifiquen como elementos secundarios del propio MapView. Esto proporciona una API intuitiva y similar a una reacción para controlar de forma declarativa funciones en el mapa.
< 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
con varias resoluciones (llamémoslas custom_pin
). Para obtener más información, vaya a Android, iOS. < Marker
coordinate = { { latitude : latitude , longitude : longitude } }
image = { { uri : 'custom_pin' } }
/ >
Nota: También puede pasar los datos binarios de la imagen como image={require('custom_pin.png')}
, pero esto no se adaptará bien a los diferentes tamaños de pantalla.
Nota: Esto tiene implicaciones de rendimiento; si desea una solución más sencilla, opte por una imagen personalizada (ahórrese el dolor de cabeza)
< 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 > ;
Para Android: agregue la siguiente línea en su AndroidManifest.xml
< uses-permission android : name = " android.permission.INTERNET " />
Para IOS: configure App Transport Security en su aplicación
Esta biblioteca funciona con Fabric utilizando la nueva capa de interoperabilidad del renderizador.
Hay un mensaje de advertencia que indica que esos pasos no son necesarios; pero hasta ahora no hemos podido hacer que el ejemplo funcione sin ellos.
Abra su archivo de configuración : busque el archivo react-native-config
en el directorio de su proyecto.
Agregue la siguiente configuración : incluya la matriz unstable_reactLegacyComponentNames
para las plataformas Android e iOS como se muestra a continuación:
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' ,
] ,
} ,
} ,
} ;
Consulte el proyecto de ejemplo para verlo en acción.
Los mosaicos se pueden almacenar localmente dentro del dispositivo usando el esquema de mosaico xyz y también se pueden mostrar como superposición de mosaicos. Esto es útil especialmente para el uso de mapas sin conexión cuando hay mosaicos disponibles para la región del mapa seleccionada dentro del almacenamiento del dispositivo.
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 > ;
Para Android: LocalTile todavía se superpone sobre los mosaicos del mapa original. Significa que si el dispositivo está en línea, los mosaicos subyacentes aún se descargarán. Si no desea descargar/mostrar mosaicos originales, establezca mapType en 'ninguno'. Por ejemplo:
<MapView
mapType={Platform.OS == "android" ? "none" : "standard"}
>
Consulte OSM Wiki para saber cómo descargar mosaicos para su uso sin conexión.
Coloque los componentes que desea superponer MapView
debajo de la etiqueta de cierre MapView
. Coloque absolutamente estos elementos.
render ( ) {
return (
< MapView
region = { this . state . region }
/ >
< OverlayComponent
style = { { position : "absolute" , bottom : 50 } }
/ >
) ;
}
El <MapView provider="google" googleMapId="yourStyledMapId" />
Google Maps en iOS y Android admite estilos a través de la plataforma en la nube de Google, los mapas con estilos se publican bajo un googleMapId, simplemente configurando la propiedad googleMapId en MapView puede usarlo mapa con estilo más información aquí: id de mapa de Google
El componente <MapView />
y sus componentes secundarios tienen varios eventos a los que puede suscribirse. Este ejemplo muestra algunos de ellos en un registro a modo de demostración.
Se puede cambiar la posición de la vista del mapa usando referencias y métodos de componentes, o pasando una propiedad region
actualizada. Los métodos del componente permitirán animar a una posición determinada como lo haría la API nativa.
Se puede hacer que el componente <MapView />
funcione con la API animada, declarando toda la propiedad region
como un valor animado. Esto permite animar el zoom y la posición de MapView junto con otros gestos, dando una sensación agradable.
Además, las vistas de marcadores pueden utilizar la API animada para mejorar el efecto.
Problema: dado que Android necesita representar sus vistas de marcadores como un mapa de bits, es posible que las API de animaciones no sean compatibles con las vistas de marcadores. No estoy seguro de si esto se puede solucionar todavía o no.
Las coordenadas de los marcadores también se pueden animar, como se muestra en este ejemplo:
Hasta ahora, <Circle />
, <Polygon />
y <Polyline />
están disponibles para pasarlos como elementos secundarios al componente <MapView />
.
Las polilíneas degradadas se pueden crear usando el accesorio strokeColors
del componente <Polyline>
.
Los marcadores predeterminados se representarán a menos que se especifique un marcador personalizado. Opcionalmente, se puede ajustar el color del marcador predeterminado utilizando el accesorio pinColor
.
Las llamadas a marcadores pueden ser vistas de reacción completamente arbitrarias, similares a los marcadores. Como resultado, se puede interactuar con ellos como con cualquier otra vista.
Además, puede recurrir al comportamiento estándar de simplemente tener un título/descripción a través de los accesorios title
y description
del <Marker />
.
Las vistas de llamadas personalizadas pueden ser la burbuja de información sobre herramientas completa o solo el contenido dentro de la burbuja predeterminada del sistema.
Para manejar la pulsación en una subvista específica del texto destacado, utilice <CalloutSubview />
con onPress
. Vea el ejemplo Callouts.js
.
Los marcadores se pueden personalizar simplemente usando imágenes y especificarse usando el accesorio image
.
Los marcadores se pueden arrastrar y emiten eventos de arrastre continuos para actualizar otras UI durante los arrastres.
Habilite el modo lite en Android con la propiedad liteMode
. Ideal cuando se tienen varios mapas en una Vista o ScrollView.
Se puede hacer clic en los puntos de interés, puede capturar el evento para obtener su información (generalmente para obtener los detalles completos de Google Place usando el placeId).
MapView puede aceptar un valor de AnimatedRegion
como propiedad region
. Esto le permite utilizar la API animada para controlar el centro y el zoom del mapa.
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 }
/ >
) ;
}
Los marcadores también pueden aceptar un valor de AnimatedRegion
como coordenada.
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 >
) ;
}
Pase una serie de identificadores de marcadores para que el mapa se vuelva a enfocar.
Pase una serie de coordenadas para enfocar una región del mapa en dichas coordenadas.
const styles = StyleSheet . create ( {
map : {
... StyleSheet . absoluteFillObject ,
} ,
} ) ;
< MapView
style = { styles . map }
// other props
/ >
Malo:
< View >
< TextInput / >
< MapView / >
< / View >
Bien:
< View >
< MapView / >
< TextInput / >
< / View >
Los componentes que no están declarados por esta biblioteca (por ejemplo, marcadores, polilínea) no deben ser hijos del componente MapView debido a la metodología de representación única de MapView. Coloque sus componentes/vistas personalizados fuera del componente MapView y colóquelos de forma absoluta para garantizar que solo se vuelvan a representar según sea necesario. Ejemplo: Malo:
< View style = { StyleSheet . absoluteFillObject } >
< MapView style = { StyleSheet . absoluteFillObject } >
< View style = { { position : 'absolute' , top : 100 , left : 50 } } / >
< / MapView >
< / View >
Bien:
< View style = { StyleSheet . absoluteFillObject } >
< MapView style = { StyleSheet . absoluteFillObject } / >
< View style = { { position : 'absolute' , top : 100 , left : 50 } } / >
< / View >
Fuente: #1901
<MapView>
al usar Apple Maps en mapType: "standard"
a veces falla cuando pones la aplicación en segundo plano o cambias a otra aplicación. Esto es solo un problema en XCode que usa Metal API Validation y no sucederá en producción. Para eliminar este problema incluso durante la depuración en XCode, vaya a Edit Scheme... -> Run (Debug) -> Diagnostics
y desmarque Metal -> API Validation
. (h/t @Simon-TechForm).
Fuente: #3957 (comentario)
Si se llama infinitamente a cambiar el estado en onRegionChangeComplete
, agregue una condición para limitar que estas llamadas ocurran solo cuando el cambio de región se realizó como resultado de la acción de un usuario.
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 }