4
votes

I have a MKMapView and a never changing CLLocationCoordinate2D. What I am trying to do is center the map so that this coordinate will be placed at the bottom center of the map. I am able to center the map on this coordinate with the simple:

MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(mapCenter, 10000, 10000);
[self.mapView setRegion:viewRegion animated:YES];

But how can I make it so that the map centers on the point that would make this mapCenter coordinate be placed at the bottom of the map? I would like it to work regardless of the initial zoom level of the map if possible.

3

3 Answers

8
votes

I wrote you a quick method that should do the trick...

After getting a MKCoordinateRegion with the location coordinate centered, you can create a new CLLocationCoordinate2D center point by adding a fraction of that region's latitudinal span (in this case, a fourth). Create a new coordinate region using the new center point and the old region's span, set it as the region of the MKMapView, and you're good to go.

P.s. - If you want the location centered all the way at the bottom, create the new CLLocationCoordinate2D center point by adding half of the region's latitudinal span (instead of a fourth).

-(void)setLocation:(CLLocationCoordinate2D)location inBottomCenterOfMapView:(MKMapView*)mapView
{
    //Get the region (with the location centered) and the center point of that region
    MKCoordinateRegion oldRegion = [mapView regionThatFits:MKCoordinateRegionMakeWithDistance(location, 800, 800)];
    CLLocationCoordinate2D centerPointOfOldRegion = oldRegion.center;

    //Create a new center point (I added a quarter of oldRegion's latitudinal span)
    CLLocationCoordinate2D centerPointOfNewRegion = CLLocationCoordinate2DMake(centerPointOfOldRegion.latitude + oldRegion.span.latitudeDelta/4.0, centerPointOfOldRegion.longitude);

    //Create a new region with the new center point (same span as oldRegion)
    MKCoordinateRegion newRegion = MKCoordinateRegionMake(centerPointOfNewRegion, oldRegion.span);

    //Set the mapView's region
    [worldView setRegion:newRegion animated:YES];
}

Here's what you'd get with the method above.

3
votes

Great jop Matthew! Thanks!

Here the same solution in SWIFT 3:

func setLocation(location: CLLocationCoordinate2D, inBottomCenterOfMapView: MKMapView) {
    let oldRegion = mapView.regionThatFits(MKCoordinateRegionMakeWithDistance(location, 800, 800))
    let centerPointOfOldRegion = oldRegion.center
    let centerPointOfNewRegion = CLLocationCoordinate2DMake(centerPointOfOldRegion.latitude + oldRegion.span.latitudeDelta/4.0, centerPointOfOldRegion.longitude)
    let newRegion = MKCoordinateRegionMake(centerPointOfNewRegion, oldRegion.span)
    worldView.setRegion(newRegion, animated: true)
}
0
votes

Just a note to say the solution above doesn't really change the mapcenter, just shifts the map view and displays a point at the bottom. For example, if you use the code above and are updating the map view based on the device heading, when you rotate the device, the rotation is NOT around the adjusted center (at the bottom of the view)...it is still around the middle of the view, which is the center of the device. An annotated pin (at the bottom of the view) then floats around the map view on a radius equidistant from the new center, and may disappear from view (as screen width < height).

To resolve this, set constraints so the mapview is pinned to the top layout guide, then add a constraint to the mapview based on the device screen resolution that matches the screen width, and for height, offsets the map BELOW the main view (for example, set the height of map view at 1.7 times larger than the screen) In Swift 4:

let screenSize = UIScreen.main.bounds
let screenWidth = screenSize.width
let screenHeight = screenSize.height*1.7

let widthConstraint = NSLayoutConstraint(item: self.yourMapView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: screenWidth)
self.yourMapView.addConstraint(widthConstraint)

let heightConstraint = NSLayoutConstraint(item: self.yourMapView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: screenHeight)    
self.yourMapView.addConstraint(heightConstraint)