Компоненты React Native Map для iOS + Android
Этот проект поддерживается небольшой группой людей, и любая помощь с проблемами и запросами на включение всегда приветствуется. Если вы можете и хотите внести свой вклад, пожалуйста, прочтите правила.
См. инструкции по установке.
См. инструкции по установке для включенного примера проекта.
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: настройте App Transport Security в своем приложении.
Эта библиотека работает с Fabric, используя новый слой взаимодействия с рендерером.
Появится предупреждающее сообщение о том, что в этих действиях нет необходимости; но нам пока не удалось заставить пример работать без них.
Откройте файл конфигурации : найдите файл react-native-config
в каталоге вашего проекта.
Добавьте следующую конфигурацию : включите массив unstable_reactLegacyComponentNames
для платформ Android и iOS, как показано ниже:
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" />
Карты Google на iOS и Android поддерживают стилизацию через облачную платформу Google. Стилизованные карты публикуются под googleMapId, просто установив для свойства googleMapId значение MapView, которое вы можете использовать. стилизованная карта, подробнее здесь: идентификатор карты Google
Компонент <MapView />
и его дочерние компоненты имеют несколько событий, на которые вы можете подписаться. В этом примере некоторые из них отображаются в журнале в качестве демонстрации.
Положение вида карты можно изменить, используя ссылки и методы компонента, или передав обновленную опору region
. Методы компонента позволят анимировать заданную позицию, как это мог бы сделать собственный API.
Компонент <MapView />
можно заставить работать с Animated API, объявив весь реквизит region
как анимированное значение. Это позволяет анимировать масштабирование и положение MapView вместе с другими жестами, создавая приятное ощущение.
Кроме того, представления маркеров могут использовать анимированный API для усиления эффекта.
Проблема. Поскольку Android необходимо отображать представления маркеров в виде растрового изображения, API-интерфейсы анимации могут быть несовместимы с представлениями маркеров. Не уверен, можно ли это обойти или нет.
Координаты маркеров также можно анимировать, как показано в этом примере:
На данный момент <Circle />
, <Polygon />
и <Polyline />
доступны для передачи в качестве дочерних элементов компоненту <MapView />
.
Градиентные полилинии можно создавать с помощью свойства strokeColors
компонента <Polyline>
.
Маркеры по умолчанию будут отображаться, если не указан пользовательский маркер. При желании можно настроить цвет маркера по умолчанию, используя свойство pinColor
.
Выноски к маркерам могут быть совершенно произвольными реагирующими представлениями, похожими на маркеры. В результате с ними можно взаимодействовать, как и с любым другим представлением.
Кроме того, вы можете вернуться к стандартному поведению, просто имея заголовок/описание через реквизиты title
и description
<Marker />
.
Пользовательские представления выносок могут представлять собой всю всплывающую подсказку или только содержимое внутри системной всплывающей подсказки по умолчанию.
Для обработки нажатия на определенный подпредставление выноски используйте <CalloutSubview />
с onPress
. См. пример Callouts.js
.
Маркеры можно настроить, просто используя изображения, и указать их с помощью свойства image
.
Маркеры можно перетаскивать, и они генерируют события непрерывного перетаскивания для обновления другого пользовательского интерфейса во время перетаскивания.
Включите облегченный режим на Android с помощью реквизита liteMode
. Идеально подходит при наличии нескольких карт в представлении или прокрутке.
Poi кликабельны, вы можете поймать событие, чтобы получить информацию о нем (обычно, чтобы получить полную информацию из Google Place, используя PlaceId).
MapView может принимать значение AnimatedRegion
в качестве свойства region
. Это позволяет вам использовать Animated 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>
с использованием Apple Maps в mapType: "standard"
иногда приводит к сбою при фоновом режиме приложения или переключении на другое приложение. Это проблема только в XCode с использованием проверки Metal API, и она не произойдет в рабочей среде. Чтобы устранить эту проблему даже во время отладки в 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 }