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
Related
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 am using react-native-maps and it works great. But I have two problems.
I am able to follow user location automatically using the followsUserLocation but when I move the map it keeps dragging me back to the user location. How could I fix this?
I want to have refresh button, and when the user press the button, I want my map view to follow user location.
constructor() {
super();
this.state = {
followsUserLocation: true,
};
}
mapView() {
return(
<MapView style={styles.map}
showsUserLocation
followsUserLocation={this.state.followsUserLocation}
initialRegion={{
latitude: 37.523814,
longitude: 126.927494,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421}}/>
)
}
Any comments or advise would be really appreciated! Thanks in advance!
Try onUserLocationChange callback and set your region accordingly using setState
state = {
showsUserLocation: true,
followsUserLocation : true,
mapRegion: {
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
},
};
<MapView
style={{ flex: 1 }}
region={this.state.mapRegion}
//use this callback to update the regions
onUserLocationChange={event => console.log(event.nativeEvent)}
showsUserLocation={this.state.showsUserLocation}
followsUserLocation={this.state.followsUserLocation}
/>
if you are working with Reack Hook
you can create a var instead of useState.
In my case to prevent the app from crashing handled with the ternary condition.
var liveMap = {
mapRegion: {
latitude: lattitude ? lattitude : 19.88134866090193,
longitude: longitude ? longitude : 73.97658792586263,
latitudeDelta: 0.0022,
longitudeDelta: 0.0021,
},
<MapView
mapType="satellite"
style={{ height: 400, width: "100%" }}
showsUserLocation={false}
zoomEnabled={true}
zoomControlEnabled={true}
followsUserLocation={true}
// onUserLocationChange={(event) => console.log("this is event",event.nativeEvent)}
showsUserLocation={true}
followsUserLocation={true}
region={liveMap.mapRegion}
// initialRegion={{
// latitude: lattitude ? lattitude : 19.88134866090193,
// longitude: longitude ? longitude : 73.97658792586263,
// latitudeDelta: 0.0022,
// longitudeDelta: 0.0021,
// }}
>
<Marker
coordinate={{
latitude: lattitude ? lattitude : 19.88134866090193,
longitude: longitude ? longitude : 73.97658792586263,
}}
title={"JavaTpoint"}
description={"Java Training Institute"}
/>
</MapView>
i' ve using react-native-map air bnb to render a google map in my native app.
The map and marker is showed up but the marker can't drag.
this is my script
<View style={Style.mapContainer}>
<GeoLocation onSetInitalPos={this.onSetInitialPosition}
onSetLastPos={this.onSetLastPosition}/>
<MapView style={Style.map} region={this.state.region} onRegionChange={this.onRegionChange}>
<MapView.Marker draggable={this.state.draggable}
coordinate={this.state.marker.latlng}
title={this.state.marker.title}
description={this.state.marker.description}
onDrag={() => console.log('onDrag')}
/>
</MapView>
<AutoCompleteMap onSetNewPlace={this.setMarkerPosition}/>
</View>
According to docs of react-native-maps draggable:
This is a non-value based prop. Adding this allows the marker to be draggable (re-positioned).
Instead of draggable={this.state.draggable}, you should be defining it like this
<MapView style={Style.map} region={this.state.region} onRegionChange={this.onRegionChange}>
<MapView.Marker
draggable
coordinate={this.state.marker.latlng}
title={this.state.marker.title}
description={this.state.marker.description}
onDragEnd={this.onUserPinDragEnd.bind(this)} />
</MapView>
Here's a snippet of working draggable marker version of my project. Nothing fancy, just using Exponent Components to import MapView, instead of npm installing and linking.
<Components.MapView
ref={(map) => this.map = map}
style={{width: Metrics.screenWidth, height: mapHeight, zIndex: 0}}
region={{
latitude: this.state.location.coords.latitude,
longitude: this.state.location.coords.longitude,
latitudeDelta: 0.0100,
longitudeDelta: 0.0100,
}}
>
<Components.MapView.Marker
key={'i29'}
draggable
onDragEnd={this.onUserPinDragEnd.bind(this)}
title={'You are here'}
coordinate={{
latitude: this.state.userLocation.coords.latitude,
longitude: this.state.userLocation.coords.longitude,
}}
/>
</Components.MapView>
And just to be sure, have you tried hold pressing the marker to drag it? It's kinda slow.
Say I have a map defined in react native this way :
render() {
return (
<View style={{flex: 1, position: 'relative'}}>
<MapView
style={styles.map}
showsUserLocation={this.state.showsUserLocation}
region={{
latitude: 48.8534100,
longitude: 2.3378000,
latitudeDelta: 0.12,
longitudeDelta: 0.065
}}
onRegionChangeComplete={
() => {
// How to retrieve coordinates and Delta when user moves the map
console.log(this.region);
}
} />
</View>
);
}
How to retrieve the coordinates and Delta when the user moves on the map ?
Here is one way to do this...
In your render() function, set onRegionChangeComplete like this:
onRegionChangeComplete={this.onRegionChangeComplete}
Then define the callback function in your component, e.g. below the render() function:
onRegionChangeComplete: function(region) {
console.log(region.longitude);
console.log(region.latitude);
}
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;