Making the Map Zoom to User Location and Annotation (Swift 2)

Making the map zoom to user location and annotation (swift 2)

It just jumps right back to the user's location, because didUpdateLocations method is called many times. There are two solutions.

1) Use requestLocation

If you use requestLocation method instead of startUpdatingLocation, didUpdateLocations method is called only once

if #available(iOS 9.0, *) {
locationManager.requestLocation()
} else {
// Fallback on earlier versions
}

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLoction: CLLocation = locations[0]
let latitude = userLoction.coordinate.latitude
let longitude = userLoction.coordinate.longitude
let latDelta: CLLocationDegrees = 0.05
let lonDelta: CLLocationDegrees = 0.05
let span:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, lonDelta)
let location: CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
let region: MKCoordinateRegion = MKCoordinateRegionMake(location, span)
self.map.setRegion(region, animated: true)
self.map.showsUserLocation = true
}

2) Use flag

var isInitialized = false

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if !isInitialized {
// Here is called only once
isInitialized = true

let userLoction: CLLocation = locations[0]
let latitude = userLoction.coordinate.latitude
let longitude = userLoction.coordinate.longitude
let latDelta: CLLocationDegrees = 0.05
let lonDelta: CLLocationDegrees = 0.05
let span:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, lonDelta)
let location: CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
let region: MKCoordinateRegion = MKCoordinateRegionMake(location, span)
self.map.setRegion(region, animated: true)
self.map.showsUserLocation = true
}
}

Zoom to fit current location and annotation on map

MKMapRectUnion computes and returns a new rect, nothing more. You need to tell the mapView to set its visible area to that new rect:

myMapView.setVisibleMapRect(zoomRect, animated: true)

MapKit zoom to user current location

I faced similar issue and wasted 4 days thinking whats going wrong. Finally resolved with creating these lines of code in viewDidLoad Method :

    //Zoom to user location
let noLocation = CLLocationCoordinate2D()
let viewRegion = MKCoordinateRegionMakeWithDistance(noLocation, 200, 200)
mapView.setRegion(viewRegion, animated: false)
mapView.showsUserLocation = true

In ViewDidLoad Method add these new changes code :

override func viewDidLoad() {

super.viewDidLoad()

let locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest

// Check for Location Services
if (CLLocationManager.locationServicesEnabled()) {
locationManager.requestAlwaysAuthorization()
locationManager.requestWhenInUseAuthorization()
}

//Zoom to user location
if let userLocation = locationManager.location?.coordinate {
let viewRegion = MKCoordinateRegionMakeWithDistance(userLocation, 200, 200)
mapView.setRegion(viewRegion, animated: false)
}

self.locationManager = locationManager

DispatchQueue.main.async {
self.locationManager.startUpdatingLocation()
}

}

Hope this helps to resolve your issue. Feel free to post comment if any further issue. Thanks

Swift zoom in on location

Use this extension, can be helpful for your needs

extension MKMapView {
func zoomToUserLocation() {
self.zoomToUserLocation(latitudinalMeters: 1000, longitudinalMeters: 1000)
}

func zoomToUserLocation(latitudinalMeters:CLLocationDistance,longitudinalMeters:CLLocationDistance)
{
guard let coordinate = userLocation.location?.coordinate else { return }
self.zoomToLocation(location: coordinate, latitudinalMeters: latitudinalMeters, longitudinalMeters: longitudinalMeters)
}

func zoomToLocation(location : CLLocationCoordinate2D,latitudinalMeters:CLLocationDistance = 100,longitudinalMeters:CLLocationDistance = 100)
{
let region = MKCoordinateRegionMakeWithDistance(location, latitudinalMeters, longitudinalMeters)
setRegion(region, animated: true)
}

}

Use in your code like this

@IBOutlet weak var mapView: MKMapView!

override func viewDidLoad() {
super.viewDidLoad()

let address = (community!["address"] as AnyObject)

let location : String = address as! String
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(location) { (placemarks, error) in
if let placemarks = placemarks {
if placemarks.count != 0 {
let annotation = MKPlacemark(placemark: placemarks.first!)
self.mapView.addAnnotation(annotation)
//Using it
self.mapView.zoomToLocation(location: annotation.coordinate)

}
}
}
}

Hope this helps

Zooming MKMapView to fit annotation pins?

You've got it right.

Find your maximum and minimum latitudes and longitudes, apply some simple arithmetic, and use MKCoordinateRegionMake.

For iOS 7 and above, use showAnnotations:animated:, from MKMapView.h:

// Position the map such that the provided array of annotations are all visible to the fullest extent possible. 
- (void)showAnnotations:(NSArray *)annotations animated:(BOOL)animated NS_AVAILABLE(10_9, 7_0);

Zooming Out to show User Location/Annotation

So do some thinking on this.

If you don't want the user's location to be shown, turn it off the show current location flag for the map.

Turn on the location manager and ask for location updates.

in the location manager delegate method that gives you location updates, take the user's new location, and average it with the annotation you want to show (lat1 + lat2)/2, (long1 + long2)/2.

That'll give you a center-point between the 2. Then take the latitude delta between those two points, the longitude delta between those two points, multiply those deltas by a small scaling factor like 1.1 or 1.2, so the two points aren't right at the edges of the screen,, and feed those numbers into MKCoordinateSpanMake, and use the resulting span, plus the center point, to create a coordinate region, and set the map to that coordinate region.

How can i increase zoom in Apple Mapkit with multiple annotations in iOS

The longitudeDelta and latitudeDelta for a MKCoordinateSpan are measured in degrees. There are only 180 degrees of latitude from the north pole to the south pole, so using 200 for that parameter is not very sensible.

Since you want to show just the region of a city on the map, you can use this other initialiser that takes in distances in meters, if you know how big the cities that your app is handling usually are.

For example,

let coordinateRegion = MKCoordinateRegion(center: cityLocation, latitudinalMeters: 30000, longitudinalMeters: 30000)

If your cities have varying sizes, or you don't know how big they are, then another way is to calculate the range of latitudes and longitudes of the hotels, and use that to create an MKCoordinateSpan.

var minLat: CLLocationDegrees = 90
var maxLat: CLLocationDegrees = -90
var minLong: CLLocationDegrees = 180
var maxLong: CLLocationDegrees = -180
for data in hotelListData {
// ... you annotation code ...

guard let hotel = data.hotel else { continue }
if hotel.latitude < minLat { minLat = hotel.latitude }
if hotel.latitude > maxLat { maxLat = hotel.latitude }
if hotel.longitude < minLong { minLong = hotel.longitude }
if hotel.longitude > maxLong { maxLong = hotel.longitude }
}
let latRange = max(0.01, maxLat - minLat) // if the range is too small, make it at least 0.01
let longRange = max(0.01, maxLong - minLong)
let coordinateRegion = MKCoordinateRegion(
center: cityLocation,
span: MKCoordinateSpan(latitudeDelta: latRange, longitudeDelta: longRange)

MKMapView zoom User Location and Annotation

If I understand well, you want those two annotations to be visible with maximum possible zoom. I found this solution that does not reqire any calculations.

// You have coordinates
CLLocationCoordinate2D user = ...;
CLLocationCoordinate2D annotation = ...;
// Make map points
MKMapPoint userPoint = MKMapPointForCoordinate(user);
MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation);
// Make map rects with 0 size
MKMapRect userRect = MKMapRectMake(userPoint.x, userPoint.y, 0, 0);
MKMapRect annotationRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0);
// Make union of those two rects
MKMapRect unionRect = MKMapRectUnion(userRect, annotationRect);
// You have the smallest possible rect containing both locations
MKMapRect unionRectThatFits = [mapView mapRectThatFits:unionRect];
[mapView setVisibleMapRect:unionRectThatFits animated:YES];

CoreLocation and MapKit structures are hell.



Related Topics



Leave a reply



Submit