How can I keep a pin centered on a map whilst I move (via Pan Gesture) another view vertically over the map such that the pin remains above the overlay (not an actual MapKit overlay).
See attached screenshots for the first and final states.
I've got the CGRect of the space between the overlay and the top of the screen as the user pan's up / down. However, how I use that to move the map and pin whilst zooming into the map as the user pans upward..and zoom back out again when the user pans downward, has eluded me so far.
I've tried different approaches, from attempting to adjust the visible rect to adjusting the map view's frame. The answer may lie in some MKMapRect / Region trickery..
(Hand icon by Freepik CC BY 3.0)
Actually, keithbhunter's code is slow because besides updating the region faster than it can load it, the map is also changing height which causes extra overhead!
I updated the code so that it runs smooth.
With this code what i do is keep the map view the same size but instead i move the point of center to compensate for the height of the sliding view.
For this code to work, you have to modify keithbhunter's setup so that the mapView's bottom constraint is pinned completely to the superview's bottom (and not to the slidingView (so that the mapView is always the same size as the super view). For the rest the setup is the same.
Also it is possible to customize the amount of zoom with the variable maxMetersDistance
Here i'm, always centering on the Eifel tower
import UIKit
import MapKit
class ViewController: UIViewController {
@IBOutlet weak var mapView: MKMapView!
@IBOutlet weak var slidingView: UIView!
@IBOutlet weak var slidingViewHeight: NSLayoutConstraint!
var maxMetersDistance:CGFloat = 10000.0; // customize this to set how far the map zooms out of the interest area
override func viewDidLoad() {
super.viewDidLoad()
let pan = UIPanGestureRecognizer(target: self, action: "viewDidPan:")
self.slidingView.addGestureRecognizer(pan)
firstTimeCenter()
}
func firstTimeCenter(){
var coordinate = CLLocationCoordinate2D(latitude: 48.8582, longitude: 2.2945)
let region = MKCoordinateRegionMakeWithDistance(coordinate, Double(maxMetersDistance), Double(maxMetersDistance))
self.mapView.setRegion(region, animated: true)
}
func reloadMap() {
let height = CGFloat(self.slidingViewHeight.constant)
var regionDistance = (maxMetersDistance / self.view.frame.height) * height
regionDistance = maxMetersDistance - regionDistance
var coordinate = CLLocationCoordinate2D(latitude: 48.8582, longitude: 2.2945)
var mapRect = mapView.visibleMapRect;
var metersPerMapPoint = MKMetersPerMapPointAtLatitude(coordinate.latitude);
var metersPerPixel = CGFloat(metersPerMapPoint) * CGFloat(mapRect.size.width) / CGFloat(mapView.bounds.size.width);
var totalMeters = Double(metersPerPixel) * Double(height/2)
coordinate = self.translateCoord(coordinate, MetersLat: -totalMeters, MetersLong: 0.0)
let region = MKCoordinateRegionMakeWithDistance(coordinate, Double(regionDistance), Double(regionDistance))
self.mapView.setRegion(region, animated: false)
}
func viewDidPan(panGesture: UIPanGestureRecognizer) {
let location = panGesture.locationInView(self.view)
self.slidingViewHeight.constant = self.view.frame.size.height - location.y
self.reloadMap()
}
func translateCoord(coord:CLLocationCoordinate2D, MetersLat:Double, MetersLong:Double)->CLLocationCoordinate2D{
var tempCoord = CLLocationCoordinate2D()
var tempRegion = MKCoordinateRegionMakeWithDistance(coord, MetersLat, MetersLong);
var tempSpan = tempRegion.span;
tempCoord.latitude = coord.latitude + tempSpan.latitudeDelta;
tempCoord.longitude = coord.longitude + tempSpan.longitudeDelta;
return tempCoord;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With