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
Ruby: Loaderror - Library Not Found for Class Digest::Sha1 -- Digest/Sha1
Uibezierpath Subclass Initializer
Swiftui Animation and Subsequent Reverse Animation to Original State
Screen Recording When My iOS App Is in Background with Replaykit
Swift iOS Record Video and Audio with Avfoundation
Admob Interstitial Alway Returns False
How to Instantiate and Load a View Controller Before Segueing to It Using Swift
Swiftui - Scrollviewreader's Scrollto Does Not Scroll
How to Add Followed Text to Uitextfield
Iad Interstitials Not Showing Consistently? and Not at All on the Simulator
iOS Swift App with More Photos: Performance and Storage Suggestions
How to Pass a Swift Object to JavaScript (Wkwebview/Swift)
Can't Dismiss Navigation Controller in Swift
iOS Uiimagepickercontroller: Any Way of Getting the Date of the Chosen Picture
Mirror Not Working in Swift When Iterating Through Children of an Objective-C Object
Displaying Strings in iOS Randomly Without Repeating Them
Return Uiimage Array from Parse Query Block
Mirror Not Working in Swift When Iterating Through Children of an Objective-C Object