this is my wrong code, it should give you an Idea of what I wanna achieve
let destCoordinates = CLLocationCoordinate2DMake(lat, long)
let annonation = MKPointAnnotation()
annonation.coordinate = destCoordinates
clientMap.addAnnotation(annonation)
self.clientMap.setRegion(MKCoordinateRegion(destCoordinates), animated: true)
You can't "just" set the the region to a coordinate. A map region consists not only of a coordinate (where the centre of the region is), but also a span (the width and height of that region). So saying something like "set the region of this map so that the centre is (0, 0)" makes no sense because you are missing the width and height of the region.
This means that you have to actively think about exactly how you want your region's span to be. In other words, how far zoomed in do you want your map to be?
If you want to remain at the same zoom level, for example, you could do this:
self.clientMap.setRegion(MKCoordinateRegion(center: destCoordindates, span: self.clientMap.region.span), animated: true)
But most of the time you probably want to zoom in to wherever your destCoordinates is for a good user experience. Try playing around with different values for the span, for example:
self.clientMap.setRegion(MKCoordinateRegion(center: destCoordindates, span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)), animated: true)
You cannot simply cast coordinates to a region. A region takes coordinates as its center and a span as its dimensions. Read the documentation here.
This is the initializer:
MKCoordinateRegion(center: CLLocationCoordinate2D, span: MKCoordinateSpan)
Related
is it possible to animate my marker rotation using MGLSymbolStyleLayer's iconRotation property ? or is there any other way to rotate my marker smoothly ?
I just want to rotate my marker smoothly , as of now the rotation is fine but it is quite snappy. Also i get different bearing for different markers from the server, is there any way i can rotate my marker using MGLPointAnnotation only ?. My use case is that i want different degree rotation for different markers (each of same icon)
let point = MGLPointAnnotation()
point.coordinate = CLLocationCoordinate2D(latitude: 30.699335, longitude: 76.836422)
let shapeSource = MGLShapeSource(identifier: "marker-source", shape: point, options: nil)
shapeLayer = MGLSymbolStyleLayer(identifier: "marker-style", source: shapeSource)
if let image = UIImage(named: "auto") {
mapView.style?.setImage(image, forName: "auto")
}
shapeLayer?.iconImageName = NSExpression(forConstantValue: "auto")
CATransaction.begin()
CATransaction.setAnimationDuration(3.0)
self.shapeLayer?.iconRotation = NSExpression(forConstantValue: 120.0)
CATransaction.commit()
You can animate an MGLSymbolStyleLayer using the add live data example. You would need to set your #objc function to layer.iconRotation and have that value change every time the function is executed. You can also do the same using an MGLPointFeature or MGLPointAnnotation as a source for an MGLSymbolStyleLayer. Please take a look at the Mapbox Add markers and shapes documentation here to see the different features that are supported.
In my project I am using google map. I am enabling the current location dot like this:
self.mapView?.isMyLocationEnabled = true
After that I am getting the current location latitude and longitude like this:
guard let currentLat = self.mapView?.myLocation?.coordinate.latitude,
let currentLan = self.mapView?.myLocation?.coordinate.longitude else {
showMessageFail(title: "Fail", myMessage: "Could not determine your current location")
return
}
And then focusing the camera on current location like this:
let currentPosition = CLLocationCoordinate2D(latitude: currentLat, longitude: currentLan)
self.mapView?.animate(toLocation: self.currentPosition)
Everything is perfectly fine, now it shows the current location dot (the blue dot on google map) on the centre of the map. Now when current location changed, say I am in a car the current location dot moves, at some point it moves out of the bounds of the map. How can I always keep the current location dot on the centre of the map and move the map not the dot. Any help would be really appreciated.
currLocation = manager.location!
let locationOfDevice: CLLocation = currLocation // this determines the location of the device using the users location
let deviceCoordinate: CLLocationCoordinate2D = locationOfDevice.coordinate // determines the coordinates of the device using the location device variabel which has in it the user location.
let span = MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1) // this determines the span in which its determined that 1 degree is 69 miles.
let region = MKCoordinateRegion(center: deviceCoordinate, span: span) // set the center equal to the device coordinates and the span equal to the span variable we have created this will give you the region.
mapView.setRegion(region, animated: true);
CLLocation *newMyLocation = [[CLLocation alloc] initWithLatitude:_locationManager.location.coordinate.latitude longitude:_locationManager.location.coordinate.longitude];
_cmarker.position = newMyLocation.coordinate;
CGPoint point1 =[_mapkitView.projection pointForCoordinate:newMyLocation.coordinate];
point1.y = -400;
GMSCameraUpdate *cameraUpdate = [GMSCameraUpdate setTarget:[_mapkitView.projection coordinateForPoint:point1]];
[_mapkitView animateWithCameraUpdate:cameraUpdate];
_cmarker.map = self.mapkitView;
//[_mapkitView setCenterCoordinate:newMyLocation.coordinate zoomLevel:_mapkitView.zoomLevel animated:YES];
[_mapkitView animateToLocation:CLLocationCoordinate2DMake(newMyLocation.coordinate.latitude, newMyLocation.coordinate.longitude)];
[_mapkitView animateToZoom:_mapkitView.camera.zoom]; // animate to that zoom level
How do you adjust the MKMapView span (zoom) without moving the map location. I am trying to do this in an attempt to limit the user from zooming out further than preferable.
Use MKCoordinateSpanMake() method, for an instance
let span = MKCoordinateSpanMake(0.05, 0.05)
Try making the zoom with the MKMapView camera instead, adjusting eyeAltitude parameter can help you
func makeZoomWithCamera(){
let newCamera: MKMapCamera = MKMapCamera(lookingAtCenter: self.mapView.camera.centerCoordinate, fromEyeCoordinate: self.mapView.camera.centerCoordinate, eyeAltitude: 10)
self.mapView.setCamera(newCamera, animated: true)
}
I'm new in Swift, and I'm trying to use MkMapView. I'd like to change the initial zoom. I searched On the API but I don't find anything.
I find only this, about zoom
mapView.zoomEnabled = true
But it isn't what I looking For.
MKMaps don't have a concept of zoom as a configurable variable. Zoom enabled pertains to user interaction. You'll need to configure something manually by setting a region that encompasses your desired zoom level.
For instance, if I wanted to zoom in on some specific coordinate, I could do:
let coordinate: CLLocationCoordinate2D = // .. populate your center
let latitudinalMeters: CLLocationDistance = 50
let longitudinalMeters: CLLocationDistance = 50
let region = MKCoordinateRegionMakeWithDistance(coordinate, latitudinalMeters, longitudinalMeters)
self.mapView.setRegion(region, animated: false) // Set to yes to animate, you said initial load so I image this won't be visible anyways.
Then, adjust the latitudinal/longitudinal dimensions to meet your desired zoom level.
If you wanted, you could probably create a category that adds zoom and calls this in the background.
From Logan's answer, update for Swift 5+
let coordinate: CLLocationCoordinate2D = // .. populate your center
let latitudinalMeters: CLLocationDistance = 50
let longitudinalMeters: CLLocationDistance = 50
let region = MKCoordinateRegion(center: coordinate, latitudinalMeters: latitudinalMeters, longitudinalMeters: longitudinalMeters)
self.mapView.setRegion(region, animated: false) // Set to yes to animate, you said initial load so I image this won't be visible anyways.
I have a MKMapView with annotation pins. When the view was loaded the nearest pin gets searched and the map will get zoomed so it shows both, the user's location and the nearest pin. I do that with [map setRegion:region animated:YES];. Everything works fine up to here. The same method is also called by tapping on a button which locates the user and then does exactly what I just described.
I also have a search field with which the user can search for map points. When the user taps on one of the search results the map sets the region so the searched pin is in the middle.
Now, there's something strange with that. I also set this region animated, at least I do the same command as above. But if the map point is too far away from the current visible part of the map it doesn't show the animation when changing the region.
Am I missing something? I've already had a look at Apples docs, they don't mention anything regarding any maximum distance for animations.
I'm looking forward to any help!
Update 1:
Just tested it again in the Simulator. An interesting fact is, that when I search for a MapPoint for the first time and then select a search result it doesn't animate. If I perform another search just after the first one and select a result it does animate. As soon as I tap on the locate button which brings the user back to his location and the closest point it doesn't animate for this setRegion: and the first search after that. But only in the Simulator, on my 4S it does exactly what I've described in the original question above.
Update 2:
In the comments I was asked to provide example coordinates.
So here the coordinates for the first step (searching of the own location and the nearest pin):
My Location: 47.227131 / 8.264251
Nearest pin: 47.251347 / 8.357191
The distance between them is about 22 kilometers. The center of the map is the center between the two pins. The distance from the center to the screen border is 1.5 times the distance between the two points which means about 33 kilometers in this case.
And here a set of coordinates for the second step (searching a map point and selecting it):
Searched pin: 46.790680 / 9.818824
The distance to the screen border is here fixed to 500 meters.
I've tested this issue with a simple demo application on iOS 6 and iOS 7 beta. It turns out that the map view actually not always animates the transition between regions. It depends on how far the regions lay apart. For example a transition from Paris to London is not animated. But if you first zoom out a little bit and then go to London it will be animated.
The documentation says:
animated: Specify YES if you want the map view to animate the
transition to the new region or NO if you want the map to center on
the specified region immediately.
But as we've seen, we can not rely on the animation. We can only tell the map view that the transition should be animated. MapKit decides whether an animation is appropriate. It tells the delegate if the transition will be animated in -(void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated.
In order to consistently animate the region change in all cases you will need to animate to a intermediate region first. Let A be the current map region and B the target region. If there is an intersection between the regions you can transition directly. (Transform the MKCoordinateRegion to an MKMapRect and use MKMapRectIntersection to find the intersection). If there is no intersection, calculate a region C that spans both regions (use MKMapRectUnion and MKCoordinateRegionForMapRect). Then first go to to region C and in regionDidChangeAnimated go to region B.
Sample code:
MKCoordinateRegion region = _destinationRegion;
MKMapRect rect = MKMapRectForCoordinateRegion(_destinationRegion);
MKMapRect intersection = MKMapRectIntersection(rect, _mapView.visibleMapRect);
if (MKMapRectIsNull(intersection)) {
rect = MKMapRectUnion(rect, _mapView.visibleMapRect);
region = MKCoordinateRegionForMapRect(rect);
_intermediateAnimation = YES;
}
[_mapView setRegion:region animated:YES];
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
if (_intermediateAnimation) {
_intermediateAnimation = NO;
[_mapView setRegion:_destinationRegion animated:YES];
}
}
This helper method is taken from here
MKMapRect MKMapRectForCoordinateRegion(MKCoordinateRegion region)
{
MKMapPoint a = MKMapPointForCoordinate(CLLocationCoordinate2DMake(
region.center.latitude + region.span.latitudeDelta / 2,
region.center.longitude - region.span.longitudeDelta / 2));
MKMapPoint b = MKMapPointForCoordinate(CLLocationCoordinate2DMake(
region.center.latitude - region.span.latitudeDelta / 2,
region.center.longitude + region.span.longitudeDelta / 2));
return MKMapRectMake(MIN(a.x,b.x), MIN(a.y,b.y), ABS(a.x-b.x), ABS(a.y-b.y));
}
The WWDC 2013 session 309 Putting Map Kit in Perspective explains how to do such complex transitions in iOS 7.
Here are the functions by #Felix rewritten to Swift 4:
// MARK: - MapView help properties
var destinationRegion: MKCoordinateRegion?
var intermediateAnimation = false
func center() {
// Center map
var initialCoordinates = CLLocationCoordinate2D(latitude: 49.195061, longitude: 16.606836)
var regionRadius: CLLocationDistance = 5000000
destinationRegion = MKCoordinateRegionMakeWithDistance(initialCoordinates, regionRadius * 2.0, regionRadius * 2.0)
centreMap(on: destinationRegion!)
}
private func mapRect(forCoordinateRegion region: MKCoordinateRegion) -> MKMapRect {
let topLeft = CLLocationCoordinate2D(latitude: region.center.latitude + (region.span.latitudeDelta/2), longitude: region.center.longitude - (region.span.longitudeDelta/2))
let bottomRight = CLLocationCoordinate2D(latitude: region.center.latitude - (region.span.latitudeDelta/2), longitude: region.center.longitude + (region.span.longitudeDelta/2))
let a = MKMapPointForCoordinate(topLeft)
let b = MKMapPointForCoordinate(bottomRight)
return MKMapRect(origin: MKMapPoint(x:min(a.x,b.x), y:min(a.y,b.y)), size: MKMapSize(width: abs(a.x-b.x), height: abs(a.y-b.y)))
}
func centreMap(on region: MKCoordinateRegion) {
var region = region
var rect = mapRect(forCoordinateRegion: region)
let intersection = MKMapRectIntersection(rect, mapView.visibleMapRect)
if MKMapRectIsNull(intersection) {
rect = MKMapRectUnion(rect, mapView.visibleMapRect)
region = MKCoordinateRegionForMapRect(rect)
intermediateAnimation = true
}
mapView.setRegion(region, animated: true)
}
// MARK: - MKMapViewDelegate
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
if intermediateAnimation, let region = destinationRegion {
intermediateAnimation = false
mapView.setRegion(region, animated: true)
}
}
I also had this problem where it would not always animate, sometimes it would just jump and dissolve instead. However, I noticed that if you animate the camera instead of the region, it consistently animates.
But using the camera, you have to set the eye distance/altitude instead of the lat/lon span. I have a simple calculation for that below which is rough, it basically just sets the altitude (in meters) to the same number of meters as the longitude span of the region. If you wanted exact accuracy you'd have to figure out the number of meters per degree for the region's latitude, which changes slightly because the earth is not a perfect sphere. Of course you could multiply that value to widen or narrow the view to taste.
Swift 4.1 example code:
/* -------------------------------------------------------------------------- */
func animateToMapRegion(_ region: MKCoordinateRegion) {
// Quick and dirty calculation of altitude necessary to show region.
// 111 kilometers per degree longitude.
let metersPerDegree: Double = 111 * 1_000
let altitude = region.span.longitudeDelta * metersPerDegree
let camera = MKMapCamera(lookingAtCenter: region.center, fromEyeCoordinate: region.center, eyeAltitude: altitude)
self.mapView.setCamera(camera, animated: true)
}
You simply have to get your current location and then call this function:
◙ import MapKit
◙ var appleMapView = MKMapView()
◙ var currentCoordinate: CLLocationCoordinate2D?
currentCoordinate must be your current location coordinates:
◙ if let currentLoc = self.currentCoordinate {
let center = CLLocationCoordinate2D(latitude: currentLoc.latitude, longitude: currentLoc.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
appleMapView.setRegion(region, animated: true)
}
To anyone who has the same question and is using Swift and is using a tableView:
I called setRegion after dismissing the tableView, and it did not show animation. This is my code before editing:
dismiss(animated: true, completion: nil)
a function that calls setRegion
Then I changed it to:
dismiss(animated: true, completion: {
a function that calls setRegion
})
This time it works.