I'm trying to build a map with clustering. At first, render everything works fine, but as soon as a user tries to move map or zoom, I'm recalculating markers/clusters postions, and app breaks on iOS with error: Exception thrown while executing UI block: * -[__NSDictionaryM setObject:forKeyedSubscript:]: key cannot be nil
or
when i filter the markers or change in marker array data its same error throw
<MapView
ref={mapRef}
rotateEnabled={false}
shouldRasterizeIOS
mapType="standard"
provider={PROVIDER_GOOGLE}
style={styles.map}
initialRegion={INITIAL_REGION}
animationEnabled
>
{data &&
data?.map(item => (
<CustomMarker
item={item}
key={item?.id}
setSelectedMarkerId={(row: any) => {
mapRef?.current?.animateToRegion(
{
latitude: Number(row?.lat),
longitude: Number(row?.long),
latitudeDelta: 0.06,
longitudeDelta: 0.06,
},
1000,
);
}}
coordinate={{
latitude: Number(item?.lat),
longitude: Number(item?.long),
}}
/>
))}
</MapView>
Error of image
Dependencies:-
react-native-map-clustering react-native-maps
I am developing a react native app which includes a react map and some markers where each has a description. Each description is too long to put on a single line, but when I try and make it a multiline string as so:
const description = `Info1: Data
Info2: Data
Info3: Data`
return (
<MapView.Marker
key = {index}
coordinate = {marker.coords}
title = {marker.country}
description = {description}
/>
)
the lower lines of the description are hidden and cannot be expanded:
How do I overide this and display all the information about the marker?
You are looking for way to customize your Callout. You need to pass a custom Callout View to your Marker. See Example below.
Code:
<MapView
style={{top: 0, left:0 , bottom: 0, right: 0, position: 'absolute'}}
initialRegion={{
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}
>
<MapView.Marker
coordinate={{latitude: 37.78825, longitude: -122.4324 }}>
<MapView.Callout>
<View style={{height: 100, width: 200}}>
<Text> Title </Text>
<Text> Long Description Even More Text</Text>
<Text>Multline Description </Text>
</View>
</MapView.Callout>
</MapView.Marker>
</MapView>
Output:
Demo:
https://snack.expo.io/#tim1717/quiet-crackers
I have a map in which I need to add a draggable marker to allow the user to pick a point.
If I choose the conventional method of
<MapView
initialRegion={{
....
}}>
<Marker coordinate={this.state.coordinates} draggable />
</MapView
It's not a very smooth feedback for the user, since the marker first needs to be long-pressed before being draggable, and also it cannot be dragged beyond the current boundaries of the map, i.e. the user needs to manually scroll the map to a different region before being able to place the marker there.
So I found a workaround by following this concept:
https://alizahid.dev/blog/keep-marker-in-center-and-move-map-around-it
<MapView
initialRegion={{
latitudeDelta: 0.02,
longitudeDelta: 0.02,
latitude: this.state.coordinates.latitude,
longitude: this.state.coordinates.longitude
}}
onRegionChange={(result) => this.setState({coordinates: result})}
style={{height: 300}}
>
<Marker coordinate={this.state.coordinates} />
</MapView>
This works almost perfect, except for the fact I'm using a separate function using Geolocation service to get the user's current location and place the marker there
componentDidMount() {
Geolocation.getCurrentPosition((position) => {
this.setState({
coordinates: {
latitude: position.coords.latitude,
longitude: position.coords.longitude
}
});
},
(error) => {
console.log(error);
alert("Couldn't get GPS location. Please try again or choose pickup point manually.");
},
{ enableHighAccuracy: true, maximumAge: 10000, timeout: 10000, showLocationDialog: true, forceRequestLocation: true})
}
When this function returns the location, the marker is moved to the correct point, BUT, the map does not scroll to the region where the marker is placed, since initialRegion does not change the region after mounting.
If I use region instead of initialRegion, the map does not scroll at all, since the onRegionChange callback is changing the state continuously and probably conflicting with the region prop.
What could be the best workaround against all the issues?
The best way is to show a marker in centre of screen by positioning it absolute.Like this
<View style={styles.markerFixed}>
<Icon
style={{
color: '#B11C01',
}}
size={30}
name={'map-marker-alt'}
solid
/>
</View>
markerFixed: {
left: 0,
right: 0,
marginLeft: 0,
marginTop: 0,
position: 'absolute',
top: '40%',
alignItems: 'center',
},
Now you can drag your map to any location.Which will show effect like marker is moving.But map is moving in actual.Now use onRegionChangeComplete function to convert updated latlang to address.And you can show that converted address above the marker like in shot.
import Geocoder from 'react-native-geocoding';
<MapView
style={styles.mapStyle}
provider={PROVIDER_GOOGLE}
region={{
latitude: lat,
longitude: long,
latitudeDelta: 0.0922 / 10,
longitudeDelta: 0.0421 / 10,
}}
onRegionChangeComplete={this.onRegionChange}
/>
convertToAddress() {
let {lat, long} = this.state;
if (this.state.firstIndication === 0) {
this.setState({firstIndication: 1});
return;
}
Geocoder.from(lat, long)
.then(json => {
var addressComponent = json.results[0].address_components[0];
this.setState({name: addressComponent.long_name});
})
.catch(error => console.warn(error));
}[![enter image description here][1]][1]
The best workaround would be using react-native-location-view
It provides you a draggable map and you can easily get the location whatever you choose by the marker.
You can refer https://www.npmjs.com/package/react-native-location-view
I'm using MapView from 'react-native-maps'
I can't get the "showsMyLocationButton" to show, so I'm implementing my own.
I want do this without using React Native's geolocation because I find it to be slower than react-native-maps prop showsUserLocation. I use onUserLocationChange event which returns the coordinates. However when firing the onUserLocationChange event and setting a state which contains the userLocation, it automatically updates the region without me explicitly asking for it.
This is my code:
display_my_location(coordinate){
alert("region changed")
this.setState({
region: {
latitude: coordinate.latitude,
longitude: coordinate.longitude,
latitudeDelta: 0.004,
longitudeDelta: 0.004
},
});
}
setUserLocation(coordinate){
//alert("User location changed MAP SHOULDNT MOVE")
this.setState({
userLocation: {
latitude: coordinate.latitude,
longitude: coordinate.longitude,
latitudeDelta: 0.004,
longitudeDelta: 0.004
}
})
}
<MapView
style={styles.map}
showsMyLocationButton={true}
onUserLocationChange={locationChangedResult => this.setUserLocation(locationChangedResult.nativeEvent.coordinate)}
initialRegion={this.state.region_amon}
showsUserLocation={true}
region={this.state.region}
mapType={this.state.map_style}
showsCompass = {true}
showsMyLocationButton={true}
chacheEnabled={false}
zoomEnabled={true}
I believe you can fix this by deleting the region prop from the MapView altogether. If you need to have the map's bounding box change programmatically you can attach a ref to the map and update in componentDidUpdate using the appropriate MapView method here:
https://github.com/react-community/react-native-maps/blob/master/docs/mapview.md#methods
I have a workaround for the above issue, we can have a custom icon on the map. After clicking on the custom icon trigger a method. In the method get the current location coordinates using Geolocation and fire animateToRegion and pass the coordinates.
Step 1: Declare mapRef
const mapRef = useRef(null);
Step 2: Assing mapRef to MapView
<View style={{flex: 1}>
<MapView
ref={mapRef}
...........
/>
<TouchableOpacity
onPress={currentLocationHandler}>
<MaterialIcons
name="my-location"
size={24}
color="black"
/>
</TouchableOpacity>
</View>
Step 3: currentLocationHandler method
const currentLocationHandler = () => {
<!-- Get location coordinates using GeoLocation npm package -->
let currentRegion = {
latitude: latitude from geolocation,
longitude: longitude from geolocation,
latitudeDelta: 0.001,
longitudeDelta: 0.001,
};
mapRef.current.animateToRegion(currentRegion, 3 * 1000);
}
I hope the above steps help you to solve the issue
I want to set a marker on MapView in React Native, but I can't find any information through official documents of MapView.
If it is not allowed in that way, how can I use existed react module such as react-googlemaps in React Native?
Thank you #naoufal.
Finally I am able to display markers on map for react native IOS.
<View style={styles.container}>
<MapView style={styles.map}
initialRegion={{
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0,
longitudeDelta: 0.0,
}}
>
<MapView.Marker
coordinate={{latitude: 37.78825,
longitude: -122.4324}}
title={"title"}
description={"description"}
/>
</MapView>
</View>
For map and container styles, I have used following styles:
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
map: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}
});
I have referred following link:
React native IOS- Display Markers on map
You can set markers using the annotations prop.
For example:
var markers = [
{
latitude: 45.65,
longitude: -78.90,
title: 'Foo Place',
subtitle: '1234 Foo Drive'
}
];
<MapView
region={...}
annotations={markers}
/>
import MapView, { Marker } from 'react-native-maps';
<View>
<MapView
style={styles.mapStyle}
initialRegion={{
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}
>
<Marker coordinate = {{latitude: 37.78825,longitude: -122.4324}}
pinColor = {"purple"} // any color
title={"title"}
description={"description"}/>
</MapView>
</View>
For those looking for a dynamic (e.g., from API), rather than hardcoded coordinates; here's the copy/paste snippet from one of the screens automatically generated by Expo CLI, included React Hooks:
import axios from "axios";
import MapView from "react-native-maps";
import { Dimensions, StyleSheet } from "react-native";
import { Marker } from "react-native-maps";
import { Text, View } from "../components/Themed";
export default function TabTwoScreen() {
const [markers, setMarkers] = useState(null);
useEffect(() => {
axios({
method: "GET",
url: "https://API_URL...",
headers: {
Authorization: `Bearer MY_TOKEN_ABC123...`,
Accept: "application/json",
},
})
.then((response) => {
setMarkers(response.data.results);
})
.catch((error) => {
console.log(error);
});
}, []); // "[]" makes sure the effect will run only once.
return (
<View style={styles.container}>
<Text style={styles.title}>Tab Two</Text>
<MapView style={styles.map}>
{markers &&
markers.map((marker: any, index: number) => (
<Marker
key={index}
coordinate={{
latitude: marker.location[1],
longitude: marker.location[0],
}}
title={marker.title}
description={marker.description}
/>
))}
</MapView>
</View>
);
}
const styles = StyleSheet.create({
// Add your styles here...
});
Updated code - 2020 | React Native 0.63
import MapView, { Marker } from "react-native-maps";
<MapView
style={styles.mapStyle}
region={{
latitude: this.state.mapLat,
longitude: this.state.mapLong,
latitudeDelta: 0.001663,
longitudeDelta: 0.002001,
}}
onRegionChangeComplete={this.onRegionChange}
>
<Marker
coordinate={{latitude: 51.5078788, longitude: -0.0877321}}
>
</Marker>
</MapView>
According to this issue, it's not exposed yet. You won't be able to use the web-React package either, React Native doesn't work like that.
Two suggestions:
Wait for the above issue to be resolved to get a proper API
Try and use WebView to link to a Google Map with an annotation
I'm not actually certain whether #2 is possible though.
import MapView from 'react-native-maps';
<View style={StyleSheet.absoluteFillObject}>
<MapView style={styles.map}
showsUserLocation //to show user current location when given access
loadingEnabled //to show loading while map loading
style={styles.map}
initialRegion={{
latitude,
longitude,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}
>
{
locations && locations.map((location, index) => {
const {
coords: { latitude, longitude }
} = location;
return (
<MapView.Marker
key={index}
coordinate={{ latitude, longitude }}
title={"title"}
description={"address"}
// onPress={this.onMarkerPress(location)}
/>
)
})
}
</MapView>
</View>```
const styles = StyleSheet.create({
map: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}
});
"dependencies": {
"native-base": "^2.13.8",
"react": "16.9.0",
"react-native": "0.61.2",
"react-native-maps": "git+https://git#github.com/react-native-community/react-native-maps.git"
},
Try using this. Hope it helps to mark for many locations. Happy Coding.
Thank you #zia_qureshi. Finally I am able to display markers on map for react native android.
import MapView, { Marker } from "react-native-maps";
const App = () => {
const [region, setRegion] = useState({
latitude: 51.5078788,
longitude: -0.0877321,
latitudeDelta: 0.009,
longitudeDelta: 0.009
});
return (
<MapView
style={{ flex: 1 }}
region={region}
onRegionChangeComplete={region => setRegion(region)}
>
<Marker coordinate={{ latitude: 51.5078788, longitude: -0.0877321 }} />
</MapView>
);
};
export default App;