I found a few other issues.
- It depends when you call this code
Doc of setRegion(_:animated:) indicates:
When setting a new region, the map may adjust the value in the region parameter so that it fits the visible area of the map precisely. This adjustment is normal and is done to ensure that the value in the region property always reflects the visible portion of the map. However, it does mean that if you get the value of that property right after calling this method, the returned value may not match the value you set. (You can use the regionThatFits(_:) method to determine the region that will actually be set by the map.)
So I had to call when mapView.setRegion animation was completed (or remove the animation by setting parameter to false.
- Looks like you have defined some wrong coordinates:
MKMapPoint eastMapPoint = MKMapPointMake(MKMapRectGetMinX(mRect), MKMapRectGetMidY(mRect)); // east should be maxX
MKMapPoint westMapPoint = MKMapPointMake(MKMapRectGetMaxX(mRect), MKMapRectGetMidY(mRect)); // west should be minX
MKMapPoint northMapPoint = MKMapPointMake(MKMapRectGetMinY(mRect), MKMapRectGetMidX(mRect)); // north should be MKMapRectGetMidX, MKMapRectGetMaxY
MKMapPoint southMapPoint = MKMapPointMake(MKMapRectGetMaxY(mRect), MKMapRectGetMidX(mRect)); // south should be MKMapRectGetMidX, MKMapRectGetMinY
CLLocationDistance wLength = MKMetersBetweenMapPoints(eastMapPoint, westMapPoint);
CLLocationDistance hLength = MKMetersBetweenMapPoints(northMapPoint, southMapPoint);
spanLat = wLength / 111000; // that is spanLon
spanLon = hLength / (111000 * cos(centreLat*3.14159/180)); // that is spanLat
With those different changes, it apparently works fine.
Here is my Swift code:
private extension MKMapView {
func mapSpan() -> (DeltaLat: Double, deltaLong: Double) {
let mRect = self.visibleMapRect
let westMapPoint = MKMapPoint(x: mRect.minX, y: mRect.midY)
let eastMapPoint = MKMapPoint(x: mRect.maxX, y: mRect.midY)
let northMapPoint = MKMapPoint(x: mRect.midX, y: mRect.maxY)//(x: mRect.minY, y: mRect.midX)
let southMapPoint = MKMapPoint(x: mRect.midX, y: mRect.minY)//(x: mRect.maxY, y: mRect.midX)
let wLength = westMapPoint.distance(to: eastMapPoint)
let hLength = southMapPoint.distance(to: northMapPoint)
let spanLat = hLength / 111000
let centreLat = (northMapPoint.coordinate.latitude + southMapPoint.coordinate.latitude) / 2
let spanLon = wLength / (111000 * cos(centreLat * .pi/180))
return (spanLat, spanLon)
}
}
I call as:
mapView.setRegion(region, animated: false) // need to set animation to false
print(mapView.mapSpan())
Or call from different thread after delay:
mapView.setRegion(region, animated: true)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
print(self.mapView.mapSpan())
}