I have a Flutter app with a map that shows user location
On the simulator, when I change the coords the marker moves.
However, on a physical device it doesn't move at all.
I have a Geolocator Stream to update the marker position
Here is my code
Position? currentPosition;
StreamSubscription<Position>? positionStream;
void listenToLocationChanges() {
LocationIndicator locationIndicator = LocationIndicator();
locationIndicator.locationIndicatorStyle = LocationIndicatorIndicatorStyle.pedestrian;
final LocationSettings locationSettings = LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 100,
);
positionStream = Geolocator.getPositionStream(locationSettings: locationSettings).listen(
(Position? position) {
print(position==null? 'Unknown' : '$position');
currentPosition = position;
GeoCoordinates geoCoordinates = GeoCoordinates (position!.latitude, position.longitude);
bearing = position.heading;
currentlat = position.latitude;
currentlong = position.longitude;
Location location = Location.withCoordinates(geoCoordinates);
location.time = DateTime.now();
location.bearingInDegrees = bearing;
locationIndicator.updateLocation(location);
_hereMapController.addLifecycleListener(locationIndicator);
_locationIndicatorList.add(locationIndicator);
},
);
}
Is there any reason why it would work in my simulator when I change the custom coords, it updates fine, but on a device it stays still at the location when opened?
Thanks in advance
I changed distance params and is now accurate
Related
My app is loading a HERE map, and works fine with a set of manually entered coordinates as the centre point.
I have implemented Geolocator in another part of the app to produce the users location which is then implemented into a function to find places near their current location & display on map.
I have now taken the Geolocator position finder and want to use it to open the map on the users location. The code uses async and await to get users coordinates.
The map open function does not want to accept async/ await, yet I have tried building it within its own class and pulling the coords, without success.
I am relatively new and any advice is greatly appreciated
Async & Await are currently red underlined in the 'function to open map', and when I change MapMarkerExample to mapMarkerExample at the top of 'function to open map', _mapMarkerExample = MapMarkerExample (_showDialog, hereMapController); is red underlined on `command to open map'
Command to open map
void _onMapCreated(HereMapController hereMapController) {
hereMapController.mapScene.loadSceneForMapScheme(MapScheme.normalDay, (MapError error) {
if (error == null) {
_mapMarkerExample = MapMarkerExample (_showDialog, hereMapController);
} else {
print("Map scene not loaded. MapError: " + error.toString());
}
});
}
Function to open map
MapMarkerExample(ShowDialogFunction showDialogCallback, HereMapController hereMapController) async {
_showDialog = showDialogCallback;
_hereMapController = hereMapController;
Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
var lat = position.latitude;
var long = position.longitude;
double distanceToEarthInMeters = 8000;
_hereMapController.camera.lookAtPointWithDistance(
GeoCoordinates(lat, long), distanceToEarthInMeters);
_setTapGestureHandler();
_showDialog("Note", "Tap markers for more.");
}
The problem is that MapMarkerExample() is a constructor and constructors cannot be executed asynchronously.
One possible way to solve this is to not set the coords in the MapMarkerExample() constructor. Just call it to create the instance. And then in a second method _setMapTarget() you can set the center coords of the map.
_setMapTarget() is marked async, so it will be executed immediately and it will not block _onMapCreated(). But it will do the magic a little bit later, fetch the position and once it has the position, it will update the camera.
If fetching the position takes to long, then you would see for that time a default camera position of the map.
void _onMapCreated(HereMapController hereMapController) {
hereMapController.mapScene.loadSceneForMapScheme(MapScheme.normalDay, (MapError? error) {
if (error == null) {
_mapMarkerExample = MapMarkerExample(_showDialog, hereMapController);
_setMapTarget(hereMapController);
} else {
print("Map scene not loaded. MapError: " + error.toString());
}
});
}
Future<void> _setMapTarget(HereMapController hereMapController) async {
Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
var lat = position.latitude;
var long = position.longitude;
double distanceToEarthInMeters = 8000;
hereMapController.camera.lookAtPointWithDistance(GeoCoordinates(lat, long), distanceToEarthInMeters);
}
I have a React Native project using react-native-maps:
getRegionForCoordinates(points) {
// points should be an array of { latitude: X, longitude: Y }
let minX, maxX, minY, maxY;
var arr = [];
Object.keys(points).map(key => {
var point = points[key];
arr.push([{latitude: point.latitude, longitude: point.longitude}])
})
points = arr;
var first = points[0];
minX = first[0].latitude;
maxX = first[0].latitude;
minY = first[0].longitude;
maxY = first[0].longitude;
// calculate rect
points.map((point) => {
minX = Math.min(minX, point[0].latitude);
maxX = Math.max(maxX, point[0].latitude);
minY = Math.min(minY, point[0].longitude);
maxY = Math.max(maxY, point[0].longitude);
});
const midX = (minX + maxX) / 2;
const midY = (minY + maxY) / 2;
const deltaX = (maxX - minX);
const deltaY = (maxY - minY);
return {
latitude : midX,
longitude : midY,
latitudeDelta : deltaX,
longitudeDelta : deltaY
};
}
componentDidMount() {
var event = this.props.event;
var mapData = JSON.parse(event.map);
var map = mapData[0];
var markers = [];
Object.keys(map.markers).map(key => {
var marker = map.markers[key];
var obj = [{ latitude: parseFloat(marker.lat), longitude: parseFloat(marker.lng) }];
markers.push(obj[0]);
});
var region = this.getRegionForCoordinates(markers);
setTimeout(() => {
this.ref.animateToRegion(region, 1);
}, 5000)
}
renderMap() {
var event = this.props.event;
var mapData = JSON.parse(event.map);
var map = mapData[0];
return (
<View>
<MapView
provider={PROVIDER_GOOGLE}
style={mapStyles.map}
ref={(map) => {
this.ref = map
}}
customMapStyle={customMapStyle}
key={ `${Date.now()}` }
>
{
map.markers.map(marker => {
return (
<EventMapMarker marker={marker} navigation={this.props.navigation} />
)
})
}
</MapView>
</View>
)
}
In this code I am trying to animate to a region based on the markers that will be displayed on the map. The latitude, longitude, latitudeDelta and longitudeDelta are correct as they work for Android.
However, on iOS it animates to a completely wrong region, both in the simulator and on the device.
Setting initialRegion or region doesn't seem to make any difference.
I have tried a bunch of different things, like animating in the onMapReady function, using a setTimeout to delay the animate, updating/downgrading react-native-maps, etc.. I don't know if this is a bug or something I have set incorrectly in my project.
React Native version is 0.59.0.
react-native-maps version is 0.27.1.
It doesn't work if you set provider={PROVIDER_GOOGLE}. Removing that, it works even on IOS. Not sure why. I am facing the same issue.
Use the timing method:
https://jakallergis.com/google-maps-in-react-native-part-3-advanced-usage
This works for me
There are several possible causes that I have found so far, depending on the exact nature of how your map is animating to the wrong region.
Centre of target is at the top left of the map.
I am not entirely certain why this one occurs. I just know that manually setting the map's position after a short timeout after it's creation seems to stop it from occurring.
const [mapStyle, setMapStyle] = useState({ height: 0 });
useEffect(() => {
setTimeout(() => {
setMapStyle({});
}, 2000);
}, []);
return <>
<MapView provider={PROVIDER_GOOGLE}
style={[StyleSheet.absoluteFillObject, mapStyle]} ...
My best guess is somewhere along the lines of this:
I tell it to align the map to a marker.
Because of some reason, a race condition of some form, perhaps, it thinks at this stage the map's height is 0x0.
Because of this, it sets the map's position to that marker but with no width or height.
Then something happens and it has to scale the map up to meet the actual width and height of the map view, but it anchors to the top left corner, so that's where the centre of the region is shown.
Manually resetting the height/width seems to kick it and stop it from thinking the map's height is 0x0, so it doesn't have the same problem.
For whatever reason, this issue for me was intermittent and also specific to iOS google maps.
Map stays at current position but zoom level is correct
This probably means your latitude delta's too large.
Specifying a region that includes any latitude value not between 90.0 or -90.0 seems to prevent the map from animating to that region. Instead it will only set the zoom level, leaving the camera at the current position.
In other words, if abs(latitude) + latitudeDelta / 2 is greater than 90, then you will see this issue.
Animating to 180.0 longitude always
Specifying a longitude delta greater than 180 will cause the map to animate to 180.0 longitude always.
I had to show locations around the user location. The locations info will arrive from the server. I am using 'for' loop to parse the location and add to map with annotation pin. As of now, it shows only the last arrived location. But the requirement is such that multiple locations should be shown with user location as Center point. As of now I am able to show only one pin. Please help how to achieve this?
for (NSDictionary* dictionary in responseDict)
{
NSString *latitudeString=[NSString stringWithFormat:#"%#",[dictionary valueForKey:#"LATITUDE"]];
double latitude=[latitudeString doubleValue];
NSString *longitudeString=[NSString stringWithFormat:#"%#",[dictionary valueForKey:#"LONGITUDE"]];
double longitude=[longitudeString doubleValue];
NSLog(#"the LATITUDE AND LONGITUDE is %f, %f",latitude,longitude);
CLLocationCoordinate2D locationCoordinate;
locationCoordinate.latitude=latitude;
locationCoordinate.longitude=longitude;
[self.mapView addAnnotation:locationCoordinate withPinColor:WKInterfaceMapPinColorPurple];
MKCoordinateSpan coordinateSpan = MKCoordinateSpanMake(0.05, 0.05);
[self.mapView setRegion:(MKCoordinateRegionMake(locationCoordinate, coordinateSpan))];
}
`
You zoom on a single location in each iteration of the loop, so eventually you end up zoomed on the last location. Sadly WKInterfaceMap doesn't have a showAnnotations method as MKMapView does, so you need to write a function yourself to achieve showing an MKCoordinateRegion including several annotations.
I haven't written any Obj-C for a while, but here's the function in Swift that shows two annotations on a Map and works on watchOS:
func showTwoMapCoordinates(first: CLLocationCoordinate2D, second: CLLocationCoordinate2D)->MKCoordinateRegion{
let center = CLLocationCoordinate2D(latitude: (first.latitude+second.latitude)/2, longitude: (first.longitude+second.longitude)/2)
var latDelta:CLLocationDegrees {
let delta = abs((first.latitude-second.latitude)*1.4)
if delta > 0 {
return delta
} else {
return 0.1
}
}
var lonDelta:CLLocationDegrees {
let delta = abs((first.longitude-second.longitude)*1.4)
if delta > 0 {
return delta
} else {
return 0.1
}
}
let span = MKCoordinateSpan(latitudeDelta: latDelta, longitudeDelta: lonDelta)
return MKCoordinateRegion(center: center, span: span)
}
To extend this to n points, where n>2, all you need to do is iterate through each pair of points you want to display, find the maximum deltas the same way as in the function above and set the center and span using the function above called on the two points that yielded the max deltas.
I have a code like below but "CLLocation loc = mapView.MyLocation;" assigne null to loc object, so i cannot take cuurent location.
How can get my current location in xamarin for ios with google map sdk for ios.
//and many other using
using Google.Maps;
public partial class MapNavigationController : UIViewController
{
MapView mapView;
public override void LoadView ()
{
base.LoadView ();
var camera = CameraPosition.FromCamera (latitude: 7.2935273,
longitude: 80.6387523,
zoom: 13);
mapView = MapView.FromCamera (RectangleF.Empty, camera);
mapView.MyLocationEnabled = true;
mapView.MapType = MapViewType.Hybrid;
CLLocation loc = mapView.MyLocation;
Console.WriteLine("tapped at " + loc.Coordinate.Latitude + "," +loc.Coordinate.Longitude);
}
}
I am not very familiar with Google Maps in iOS.
But I don't think its possible to get you current location from the MapView.
You can maybe show it (by enabling an option (showOwnLocation or something similar)).
If you want to do it the right way you have to do it with the CLLocationManager from the iOS SDK. I don't have a sample available right now but if you google it you will find some.
Hopefully this helps you.
You need to get that info from CCLocationManager, like so:
CameraPosition camera = CameraPosition.FromCamera(latitude: App.MyLatitude,
longitude: App.MyLongitude,
zoom:50);
mapView = MapView.FromCamera(CGRect.Empty, camera);
mapView.Settings.ScrollGestures = true;
mapView.Settings.ZoomGestures = true;
mapView.MyLocationEnabled = true;
mapView.MapType = MapViewType.Satellite;
CLLocation loc = iPhoneLocationManager.Location;
// My position
var Marker = new Marker()
{
Title = App.PinTitle,
Snippet = App.PinLabel,
Position = new CLLocationCoordinate2D(latitude: loc.Coordinate.Latitude, longitude: loc.Coordinate.Longitude),
Map = mapView
};
How can I center a map between two points? Sort of like when the native map application generates directions between location A and location B. I'm got a start coordinate and an end coordinate and I'll like to show two pins. I can place the pins in place, but I'm not sure how to set the center of the map.
Do I need to find the math to work out the exact distance from the points and set the map to that location? Is there a built in function for this?
this.currentMapView.SetCenterCoordinate (annotation.Coordinate, true);
Calculating the midpoint between two coordinates needs a simple formula. For example, let's say you have two coordinates: (x1,y1) and (x2,y2).
Their midpoint coordinate is: ( (x1+x2)/2, (y1+y2)/2 ).
So for example, in map coordinates, let's say you have the following start/end points:
a. long: 40, lat: 39
b. long: 41, lat: 38
Their midpoint coordinate is: ( (40+41)/2, (39+38)/2 ) = (40.5, 38.5)
So you set the map view's center coordinate to the outcome of this formula.
I am not aware of a built-in function for calculating this.
Taken from: http://codisllc.com/blog/zoom-mkmapview-to-fit-annotations/
BasicMapAnnotation is inherit class from MKAnnotation
private void GetRegion(MKMapView mapView)
{
var userWasVisible = mapView.ShowsUserLocation;
mapView.ShowsUserLocation = false; // ignoring the blue blip
// start with the widest possible viewport
var tl = new CLLocationCoordinate2D(-90, 180); // top left
var br = new CLLocationCoordinate2D(90, -180); // bottom right
foreach (var an in mapView.Annotations)
{
// narrow the viewport bit-by-bit
CLLocationCoordinate2D coordinate = ((BasicMapAnnotation) an).Coordinate;
tl.Longitude = Math.Min(tl.Longitude, coordinate.Longitude);
tl.Latitude = Math.Max(tl.Latitude, coordinate.Latitude);
br.Longitude = Math.Max(br.Longitude, coordinate.Longitude);
br.Latitude = Math.Min(br.Latitude, coordinate.Latitude);
}
var center = new CLLocationCoordinate2D
{
// divide the range by two to get the center
Latitude = tl.Latitude - (tl.Latitude - br.Latitude)*0.5
,
Longitude = tl.Longitude + (br.Longitude - tl.Longitude)*0.5
};
var span = new MKCoordinateSpan
{
// calculate the span, with 20% margin so pins aren’t on the edge
LatitudeDelta = Math.Abs(tl.Latitude - br.Latitude)*1.2
,
LongitudeDelta = Math.Abs(br.Longitude - tl.Longitude)*1.2
};
var region = new MKCoordinateRegion {Center = center, Span = span};
region = mapView.RegionThatFits(region); // adjusts zoom level too
mapView.SetRegion(region, true); // animated transition
mapView.ShowsUserLocation =
userWasVisible;
}
} ``