Summary
I'm using react-native-map and trying to use animateCamera and animateMarkerToCoordinate both at the same time but couldn't animate the animateCamera at all.
The working part so far
The "red circle" in the gif I've shared below, should be moving from one location to another location with animation.
I've taken advantage of this comment to be able to move marker with animation turning the code into functional component and it really worked.
Moving marker gif
My aim
I want the camera also move besides marker, so that the red circle should always be felt like it is centered in the phone screen. All this should occur when I press "animate" button below.
I've tried to do the same thing to the mapview what I've done to marker.
I've created a state
const [mapRef, setMapRef] = useState(null);
and supplied connection between <MapView> and mapRef state using the below line beginning with ref
return (
<View style={...}>
<MapView
ref= {mapRef => {setMapRef(mapRef);}}
initialRegion = {
...
}
...
/>
So when the button is pressed it goes inside this function and try to work animateCamera function
function animateMarkerAndCamera() {
let newCoordinate = {
latitude: 32.601,
longitude: 44.0172,
latitudeDelta: 0.012,
longitudeDelta: 0.012,
};
let Camera = {
...
}
if (myMarker) {
myMarker.animateMarkerToCoordinate(newCoordinate, 4000);
mapRef.animateCamera({Camera}, 4000)
}
}
By the way Camera adjusted like it is mentioned in docs
let Camera = {
center: {
latitude: newCoordinate.latitude,
longitude: newCoordinate.longitude,
},
pitch: 2,
heading: 20,
zoom: 40
}
So I'm expecting for it to animate just like it did for marker's animation, but not working.
Please tell me my fault.
Full code...
import React, {useState} from 'react'
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'
import MapView, { AnimatedRegion, MarkerAnimated } from 'react-native-maps';
const PlayScreen = (props) => {
const [myMarker, setMyMarker] = useState(null);
const [mapRef, setMapRef] = useState(null);
const [coordinate, setCoordinate] = useState(new AnimatedRegion({
latitude: 32.5983,
longitude: 44.0175,
latitudeDelta: 0.012,
longitudeDelta:0.012,
}));
function animateMarkerAndCamera() {
let newCoordinate = {
latitude: 32.601,
longitude: 44.0172,
latitudeDelta: 0.012,
longitudeDelta: 0.012,
};
if(myMarker){
myMarker.animateMarkerToCoordinate(newCoordinate,4000);
mapRef.animateCamera(newCoordinate, 4000);
}
}
return (
<View style={styles.container}>
<MapView
ref= {mapRef => {setMapRef(mapRef);}}
style={styles.map}
initialRegion={{
latitude: 32.5983,
longitude: 44.0175,
latitudeDelta: 0.012,
longitudeDelta: 0.012,
}}
>
<MarkerAnimated
ref={marker => {
setMyMarker(marker);
}}
image={require('../../../Assets/Images/curlingStone.png')}
coordinate={coordinate}
/>
</MapView>
<View style={styles.buttonContainer}>
<TouchableOpacity
onPress={() => animateMarkerAndCamera()}
style={[styles.bubble, styles.button]}
>
<Text>Animate</Text>
</TouchableOpacity>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
justifyContent: 'flex-end',
alignItems: 'center',
},
map: {
...StyleSheet.absoluteFillObject,
},
bubble: {
flex: 1,
backgroundColor: 'rgba(255,255,255,0.7)',
paddingHorizontal: 18,
paddingVertical: 12,
borderRadius: 20,
},
latlng: {
width: 200,
alignItems: 'stretch',
},
button: {
width: 80,
paddingHorizontal: 12,
alignItems: 'center',
marginHorizontal: 10,
},
buttonContainer: {
flexDirection: 'row',
marginVertical: 20,
backgroundColor: 'transparent',
},
});
export default PlayScreen
So, as I've explained before, I was trying to use animateCamera and animateMarkerToCoordinate together so that it could feel like my marker, the red circle, is always at the center and only the coordinates seem to be changing.
After a little research, I've found this and made mine similar to this code. Now I obtained what I wanted to achieve.Gif is here
Changes I've made were written as comments
The code is below
import {useState, useRef} from 'react'
import ... //same as before
const PlayScreen = (props) => {
const markerLatitude=32.5983
const markerLongitude=44.0175
//changed from useState to useRef
const mapRef = useRef (null);
const [myMarker, setMyMarker] = useState(null);
const [coordinate, setCoordinate] = useState(new AnimatedRegion({
latitude: markerLatitude,
longitude: markerLongitude,
latitudeDelta: 0.012,
longitudeDelta: 0.012,
}));
function animateMarkerAndCamera() {
let newCoordinate = {
latitude: 32.601,
longitude: 44.0172,
latitudeDelta: 0.012,
longitudeDelta: 0.012,
};
//camera will position itself to these coordinates.
const newCamera= {
center: {
latitude: 32.601,
longitude: 44.0172,
},
pitch: 0,
heading: 0,
//zoom: 17 --Use it when required
}
if (myMarker) {
myMarker.animateMarkerToCoordinate(newCoordinate, 4000);
//camera type, `newCamera`, used inside animateCamera
mapRef.current.animateCamera(newCamera, {duration: 4000})
}
}
return (
<View style={styles.container}>
<MapView
ref={ mapRef } //There is also change here
style={styles.map}
initialRegion={{
latitude: 32.5983,
longitude: 44.0175,
latitudeDelta: 0.012,
longitudeDelta: 0.012,
}}
//These are newly added
pitchEnabled ={false}
zoomEnabled ={false}
>
<MarkerAnimated
ref={marker => {
setMyMarker(marker);
}}
{/*any kind of image can be replaced here */}
image={require('../../../Assets/Images/curlingStone.png')}
coordinate={coordinate}
/>
</MapView>
<View style={styles.buttonContainer}>
<TouchableOpacity
onPress={() => animateMarkerAndCamera()}
style={[styles.bubble, styles.button]}
>
<Text>Animate</Text>
</TouchableOpacity>
</View>
</View>
);
}
export default PlayScreen
const styles = StyleSheet.create({ ... //same as before
Related
const [initialPosition,setInitialPosition] = useState({
latitude: 0,
longitude: 0,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
})
const locateCurrentPosition=() => {
Geolocation.getCurrentPosition(
position =>{
// console.log(JSON.stringify(position));
let currentLocation={
latitude: position.coords.latitude,
longitude: position.coords.longitude,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}
setInitialPosition(currentLocation);
// console.log(initialPosition);
}
)
}
useEffect(()=>{
locateCurrentPosition();
},[])
setInitialPosition(currentLocation); does not update state value and returns 0 for latitude and longitude. Hence current location is not being displayed in the app instead it's displaying (0,0) location on app launch. Kindly help me. If any other snippet of code is required do let me know.
Thanks in advance.
Try to this example:
import Geolocation from '#react-native-community/geolocation';
import MapView from 'react-native-maps';
const [latitude,setlatitude] = useState(0);
const [longitude,setlongitude] = useState(0);
const [coordinates,setcoordinates] = useState([]);
const locateCurrentPosition=() => {
Geolocation.getCurrentPosition(
position =>{
setlatitude(position.coords.latitude);
setlongitude(position.coords.longitude);
},
)
}
useEffect(()=>{
locateCurrentPosition();
},[])
<View style={{ flex: 1 }}>
<MapView
style={{ flex: 1, width: "100%" }}
region={{
latitude: latitude,
longitude: longitude,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}
>
<MapView.Marker
coordinate={{
latitude: latitude,
longitude: longitude,
}}
/>
</MapView>
</View>
I am trying to create a Swiggy/Zomato/FoodPanda like the app, I am trying to get user location or set delivery location on to the map.
The issue is happening on Android.
But I am not experiencing a smoothness when moving marker position, especially when zooming in and zooming out.
Map glitches when trying to move pin marker position
please suggest me for improvement and for to get smoothness experience.
I am trying a lot of logic but not getting any desired performance.
Here is my implemented code,
This is my initial setup on constructor
constructor(props) {
super(props);
this.latDelta = 0.00922 * 1.5;
this.longDelta = 0.00421 * 1.5;
this.state = {
visible: false,
address: {},
lastLat: 24.8076793,
lastLong: 93.9360916,
mapRegion: new AnimatedRegion({
latitude: 24.8076793,
longitude: 93.9360916,
latitudeDelta: this.latDelta,
longitudeDelta: this.longDelta
}),
marker: null,
region: new AnimatedRegion({
latitudeDelta: this.latDelta,
longitudeDelta: this.longDelta,
latitude: 24.8076793,
longitude: 93.9360916
}),
autoGeoMarker: {
latitude: 24.8076793,
longitude: 93.9360916,
autoMapAddress: '',
autoMapArea: ''
},
setGeoMarker: {
latitude: 24.8076793,
longitude: 93.9360916,
setMapAddress: '',
setMapArea: ''
},
mapIndicator: false,
mapAddress: '',
mapArea: '',
//-----
indicator: true,
searchModal: false
};
}
componentDidMount() {
this.getPermissionLocation();
}
Here I am asking for permission
getPermissionLocation = () => {
try {
request(
Platform.select({
android: PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION,
ios: PERMISSIONS.IOS.LOCATION_WHEN_IN_USE
})
).then(res => {
if (res == 'granted') {
this.setState({
searchModal: false
});
Geolocation.getCurrentPosition(
//Will give you the current location
position => {
let region = {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
latitudeDelta: this.latDelta,
longitudeDelta: this.longDelta
};
Alert.alert('', 'Pin Your Delivery point by moving map');
this.setState({
autoGeoMarker: region,
mapIndicator: false,
indicator: false
});
this.onRegionChange(region);
this.getAutoDetectAddress(region.latitude, region.longitude);
},
error => {
//setLocationStatus(error.message);
console.log('error ... 1 ' + error.message);
},
{
enableHighAccuracy: false,
timeout: 30000,
maximumAge: 1000
}
);
} else {
console.log('Location is not enabled');
Alert.alert(
'Enable Your Location:',
'Can not proceed, Please allow your Location permissioin.',
[{ text: 'OK', onPress: () => RNRestart.Restart() }]
);
}
});
} catch (error) {
console.log('location set error:', error);
}
};
//Get Auto Geolocation address
getAutoDetectAddress = (latitude, longitude) => {
Geocoder.from(latitude, longitude)
.then(json => {
let region = {
latitude: latitude,
longitude: longitude,
latitudeDelta: this.latDelta,
longitudeDelta: this.longDelta,
autoMapAddress: json.results[0].formatted_address,
autoMapArea: json.results[0].address_components[1].short_name
};
this.setState({
autoGeoMarker: region
});
})
.catch(error => console.warn(error));
//-----------------------
};
onRegionChange = region => {
this.setState({
region: region,
lastLat: region.latitude,
lastLong: region.longitude
});
this.getAddressInfo(region.latitude, region.longitude);
};
getAddressInfo = (latitude, longitude) => {
Geocoder.from(latitude, longitude)
.then(json => {
this.setState({
mapAddress: json.results[0].formatted_address,
mapArea: json.results[0].address_components[1].short_name
});
let region = {
latitude: json.results[0].geometry.location.lat,
longitude: json.results[0].geometry.location.lng,
latitudeDelta: this.latDelta,
longitudeDelta: this.longDelta,
setMapAddress: json.results[0].formatted_address,
setMapArea: json.results[0].address_components[1].short_name
};
this.setState({
setGeoMarker: region
});
})
.catch(error => console.warn(error));
};
render() {
return this.state.indicator ? (
<View style={{ flex: 1 }}>
<ActivityIndicator size="large" color="#ff6a00" />
</View>
) : (
<View style={{ flex: 1, flexDirection: 'column' }}>
<StatusBar backgroundColor="#ff6a00" />
<View style={styles.map}>
<MapView
style={styles.map}
region={this.state.region}
onRegionChangeComplete={this.onRegionChange}
/>
<View
style={{
flex: 1,
flexDirection: 'row',
alignItems: 'center',
position: 'absolute',
top: '4%',
left: '-3%'
}}
>
<TouchableOpacity
onPress={() => {
{
this.props.navigation.navigate('HomeScreen');
}
}}
>
<Image
style={{ width: 71, height: 51 }}
source={require('../../assets/app/mapback.png')}
/>
</TouchableOpacity>
</View>
<View style={styles.markerFixed}>
<Image style={styles.marker} source={marker} />
</View>
</View>
<View
style={{
flex: 1,
padding: 4,
backgroundColor: '#FFFFFF'
// borderTopColor: 'black',
// borderTopWidth: 1
}}
>
<View
style={{
flex: 1,
flexDirection: 'row',
alignItems: 'center',
marginTop: 15,
marginLeft: 20
}}
>
<View
style={{ flex: 0.8, alignItems: 'center', flexDirection: 'row' }}
>
<Image
style={{ width: 15, height: 20 }}
source={require('../../assets/app/mapmark.png')}
/>
<Text
style={{
fontSize: 18,
marginLeft: 15,
fontFamily: 'Nunito-Black'
}}
>
{this.state.mapArea}
</Text>
</View>
</View>
<Text
style={{
marginTop: 20,
marginLeft: 20,
fontSize: 12,
fontFamily: 'Poppins-Regular'
}}
>
{this.state.mapAddress}
</Text>
</View>
</View>
);
}
here I have doubt where to set these two function properly
this.onRegionChange(region);
this.getAutoDetectAddress(region.latitude, region.longitude);
maybe if these two functions but I am not sure. Where to implement correctly for getting the best performance.
Map glitches or bouncing (While pinching/zooming in and out) issue were caused by using region={this.state.region}
So, I used initialRegion={this.state.region} instead of region
Here is the complete example
onChangeValue = region => {
this.setState({
region
});
Geocoder.from(region.latitude, region.longitude)
.then(json => {
this.setState({
mapAddress: json.results[0].formatted_address,
mapArea: json.results[0].address_components[1].short_name
});
let region = {
latitude: json.results[0].geometry.location.lat,
longitude: json.results[0].geometry.location.lng,
latitudeDelta: 0.021,
longitudeDelta: 0.021,
setMapAddress: json.results[0].formatted_address,
setMapArea: json.results[0].address_components[1].short_name
};
this.setState({
setGeoMarker: region
});
// this.map.animateToRegion(region);
})
.catch(error => console.warn(error));
};
...
<MapView
style={{
flex: 1,
height: Dimensions.get('screen').height / 1.5,
position: 'relative',
marginBottom: this.state.marginBottom
}}
showsUserLocation={true}
initialRegion={this.state.region}
// region={this.state.region}
showsMyLocationButton={true}
onRegionChangeComplete={this.onChangeValue}
ref={ref => (this.map = ref)}
/>
<View
style={{
flex: 1,
flexDirection: 'row',
alignItems: 'center',
position: 'absolute',
top: '4%',
left: '-3%'
}}
>
<TouchableOpacity
onPress={() => {
{
this.props.navigation.navigate('MainTabScreen');
this.props.navigation.navigate('HomeScreen');
}
}}
>
{/*<Icon.MaterialIcons name="arrow-back" size={28} color="black" />*/}
<Image
style={{ width: 71, height: 51 }}
source={require('../../assets/app/mapback.png')}
/>
</TouchableOpacity>
</View>
...
In My Scenario, I have Implemented in my application Google MapView using "react-native-maps" npm package. In this package as per my requirement I have to draw a dashed circle polyline, like below mentioned image Green line should be dashed stroke style. How to change it like dashed or dotted stroke style line.
enter image description here
<Polyline
coordinates={[
{ latitude: 37.88045, longitude: -122.4324 },
{ latitude: 37.78825, longitude: -122.3903 },
]}
strokeWidth={3}
lineDashPattern={[170, 170]}
/>
You should be using <Circle/> instead of `. Here's a sample code and code snippet below. (Note: lineDashPattern is only available in iOS per doc).
import React, { Component } from 'react';
import { Text, View, StyleSheet, Dimensions } from 'react-native';
import MapView, { Marker, Circle, Polyline } from 'react-native-maps';
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
map: {
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
},
});
class MapApp extends Component {
render() {
return (
<View style={styles.container}>
<MapView style={styles.map}
initialRegion={{
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}
>
<Marker
coordinate={{ latitude: 37.78825, longitude: -122.4324 }}
/>
<Circle
center={{ latitude: 37.78825, longitude: -122.4324 }}
radius={1000}
strokeWidth={3}
strokeColor="green"
lineDashPattern={[10]} />
</MapView>
</View>
);
}
}
export default MapApp;
I have installed react-native-maps in my app but when i enter a MapView this is the output :
I followed the installation guide on github and entered the api key, but still does not display anything.
this is the code:
import React, {Component} from 'react';
import {StyleSheet, Text, View} from 'react-native';
import MapView from 'react-native-maps';
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<MapView
style={styles.map}
region={{
latitude: 41.89193,
longitude: 12.51133,
latitudeDelta: 0.015,
longitudeDelta: 0.0121,
}}
>
</MapView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
height: 400,
width: 400,
justifyContent: 'flex-end',
alignItems: 'center',
},
map: {
...StyleSheet.absoluteFillObject,
},
});
Does anyone know how I can solve this problem or what does it depend on?
thank's
You need to add provider to MapView:
import MapView, { PROVIDER_GOOGLE } from 'react-native-maps';
....
<MapView
provider={PROVIDER_GOOGLE}
style={styles.map}
region={{
latitude: 41.89193,
longitude: 12.51133,
latitudeDelta: 0.015,
longitudeDelta: 0.0121,
}}
>
</MapView>
Im trying to render a map at the current user geolocation on android device, using react-native maps.
Here is what i've got so far:
import React, { Component } from 'react';
import {
View,
StyleSheet,
Dimensions,
} from 'react-native';
import MapView from 'react-native-maps';
const {width, height} = Dimensions.get('window')
const SCREEN_HEIGHT = height
const SCREEN_WIDTH = width
const ASPECT_RATIO = width / height
const LATITUDE_DELTA = 0.0922
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO
class MapComponent extends Component {
constructor() {
super()
this.state = {
initialPosition: {
latitude: 0,
longitude: 0,
latitudeDelta: 0,
longitudeDelta: 0,
},
}
}
componentDidMount() {
navigator.geolocation.getCurrentPosition((position) => {
var lat = parseFloat(position.coords.latitude)
var long = parseFloat(position.coords.longitude)
var initialRegion = {
latitude: lat,
longitude: long,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA,
}
this.setState({initialPosition: initialRegion})
},
(error) => alert(JSON.stringify(error)),
{enableHighAccuracy: true, timeout: 20000, maximumAge: 1000});
}
renderScreen = () => {
return (
<View style={styles.container}>
<MapView
style={styles.map}
initialRegion={this.state.initialPosition}/>
</View>
);
}
render() {
return (
this.renderScreen()
);
}
}
const styles = StyleSheet.create({
container: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
justifyContent: 'flex-end',
alignItems: 'center',
},
map: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
},
});
export default MapComponent;
The map renders, but not in current device geolocation, as expected. (it renders in the middle of the ocean)
The permissions are already set at AndroidManifest.xml as:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
After 20 seconds, i get an alert saying, "Location request timed out" "code 3"
What i'm doing wrong?
I'm not sure but there is an issue ("Geolocation timed out, code 3") which looks related
For anyone else struggling with this issue on android, try removing
the maximumAge: 2000 option parameter. This option was causing
geolocation to either timeout or crash the app.
import React, {useState, useEffect} from 'react';
import {StyleSheet, Text} from 'react-native';
import MapView, {Marker} from 'react-native-maps';
import Geolocation from '#react-native-community/geolocation';
const App = () => {
const [position, setPosition] = useState({
latitude: 10,
longitude: 10,
latitudeDelta: 0.001,
longitudeDelta: 0.001,
});
useEffect(() => {
Geolocation.getCurrentPosition((pos) => {
const crd = pos.coords;
setPosition({
latitude: crd.latitude,
longitude: crd.longitude,
latitudeDelta: 0.0421,
longitudeDelta: 0.0421,
});
}).catch((err) => {
console.log(err);
});
}, []);
return (
<MapView
style={styles.map}
initialRegion={position}
showsUserLocation={true}
showsMyLocationButton={true}
followsUserLocation={true}
showsCompass={true}
scrollEnabled={true}
zoomEnabled={true}
pitchEnabled={true}
rotateEnabled={true}>
<Marker
title='Yor are here'
description='This is a description'
coordinate={position}/>
</MapView>
);
};
const styles = StyleSheet.create({
map: {
...StyleSheet.absoluteFillObject,
},
});
export default App;
It's working perfectly in mine. Only change I made was in StyleSheet.
container: {
position: 'absolute',
height : SCREEN_HEIGHT,
width : SCREEN_WIDTH,
justifyContent: 'flex-end',
alignItems: 'center',
}
Thereafter, it renders my location. You can add marker after that to show your location.
This is what worked for me. the third option is what was creating the prob.
navigator.geolocation.getCurrentPosition() =>{
},
err => {
},
{ enableHighAccuracy: false, timeout: 20000}, //this worked for me
navigator.geolocation.getCurrentPosition() is deprecated.
Use #react-native-community/geolocation instead.
npm install #react-native-community/geolocation --save
import React, { Component } from "react";
// global.currentScreenIndex = 'Dashboard';
//Import all required component
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Image,
Modal,
TouchableHighlight,
StatusBar,
FlatList,
ActivityIndicator,
Button,
NetInfo,
} from "react-native";
import MapView, { Marker } from "react-native-maps";
import Geolocation from "#react-native-community/geolocation";
const MyStatusBar = ({ backgroundColor, ...props }) => (
<View style={[styles.statusBar, { backgroundColor }]}>
<StatusBar translucent backgroundColor={backgroundColor} {...props} />
</View>
);
class Dashboard extends Component {
constructor() {
super();
this.state = {
initialPosition: {
latitude: 0,
longitude: 0,
latitudeDelta: 0,
longitudeDelta: 0,
},
};
}
componentDidMount() {
const { navigation } = this.props;
Geolocation.getCurrentPosition((info) => {
let lat = info.coords.latitude;
let long = info.coords.longitude;
console.log(lat);
console.log(long);
var initialRegion = {
latitude: lat,
longitude: long,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
};
this.setState({ initialPosition: initialRegion });
});
}
render() {
const { modalVisible } = this.state;
const { navigate } = this.props.navigation;
// const token_data = token_value();
// console.log("token_homes_2st"+token_data);
return (
<View style={styles.container}>
<MapView
style={styles.map}
initialRegion={this.state.initialPosition}
showsUserLocation={true}
/>
</View>
);
}
}
export default Dashboard;
const styles = StyleSheet.create({
container: {
justifyContent: "center",
fontWeight: "400",
color: "#000",
fontFamily:
"Inter UI,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif",
},
map: {
height: 400,
width: 400,
justifyContent: "flex-end",
alignItems: "center",
},
});
1.npm install #react-native-community/geolocation --save
2.import Geolocation from '#react-native-community/geolocation'; 3.navigator.geolocation.getCurrentPosition => Geolocation.getCurrentPosition