2015-05-17 8 views
6

Come posso tenere un perno centrato su una mappa mentre sposto (tramite Gesto) un'altra vista verticalmente sulla mappa in modo che il perno rimanga sopra la sovrapposizione (non una sovrapposizione MapKit effettiva).Come mantenere il perno e la mappa centrati sopra la sovrapposizione in movimento in un MKMapView

Vedere gli screenshot allegati per gli stati primo e finale.

Ho il CGRect dello spazio tra l'overlay e la parte superiore dello schermo mentre il pan utente è su/giù. Tuttavia, il modo in cui lo uso per spostare la mappa e il segnaposto mentre si ingrandisce la mappa mentre l'utente si sposta verso l'alto e lo zoom indietro di nuovo quando l'utente si sposta verso il basso, mi ha eluso finora.

Ho provato approcci diversi, dal tentativo di regolare il rect visibile alla regolazione della cornice della vista della mappa. La risposta potrebbe trovarsi in qualche MKMapRect/Regione inganno ..

Initial state

Final state with overlay panned upward

(icona di mano di Freepik CC BY 3,0)

+0

Hai provato 'approccio setCenterCoordinate'? –

+0

La mappa deve essere ingrandita e rimpicciolita quando si esegue la panoramica dell'overlay? – keithbhunter

+0

@keithbhunter Sì, verso l'interno mentre scorri verso l'alto e verso l'esterno mentre scorri verso il basso .. – Aodh

risposta

4
class ViewController: UIViewController { 

    @IBOutlet weak var mapView: MKMapView! 
    @IBOutlet weak var slidingView: UIView! 
    @IBOutlet weak var slidingViewHeight: NSLayoutConstraint! 


    override func viewDidLoad() { 
     super.viewDidLoad() 
     self.reloadMap() 
     let pan = UIPanGestureRecognizer(target: self, action: "viewDidPan:") 
     self.slidingView.addGestureRecognizer(pan) 
    } 

    func reloadMap() { 
     let coordinate = CLLocationCoordinate2D(latitude: 37.332363, longitude: -122.030805) 
     let height = Double(self.mapView.frame.size.height) 
     let regionDistance = 0.3 * height * height // random multiplier and exponential equation for scaling 
     let region = MKCoordinateRegionMakeWithDistance(coordinate, regionDistance, 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() 
    } 

} 

Per impostare i punti di vista, mettere una mappa visualizza e un UIView nel controller di visualizzazione. Usa l'autolayout per appuntare i lati sinistro, superiore e destro della vista della mappa sulla superview. Quindi appuntare la parte inferiore della vista della mappa nella parte superiore di UIView. Quindi, pin i lati sinistro, inferiore e destro del UIView alla superview. Infine, imposta un vincolo di altezza su UIView su qualsiasi cosa desideri inizializzare. Questo valore di altezza verrà modificato mentre l'utente trascina la vista. Ciò consente allo UIView di crescere a piacimento e di sospendere l'autolayout allo stesso tempo.

Aggiungi un @IBOutlet al controller della vista per la visualizzazione della mappa, il vincolo di altezza e UIView s' il UIView, come nel codice di cui sopra. La proprietà regionDistance è ciò che sta facendo la magia dello zoom qui. È un'equazione esponenziale (che ho inventato in modo casuale) che calcolerà la regione per maggiore o minore in base all'altezza della vista della mappa. reloadMap() usa questo per aggiornare lo zoom della mappa. La combinazione di tutto ciò è UIPanGestureRecognizer su UIView, che controlla l'altezza dello UIView, provocando l'azione di zoom sulla mappa.

Fossa: Questo costringe la mappa ad aggiornare la regione più velocemente di quanto possa caricare la regione, facendola sembrare molto nervosa. Ci sono probabilmente dei modi per aggirare questo. Diventa creativo.

La coordinata che ho utilizzato nell'esempio è la sede centrale di Apple.

Apple's HQ

5

In realtà, il codice di keithbhunter è lento perché oltre l'aggiornamento della regione più velocemente di quanto si può caricarlo, la mappa sta cambiando anche in altezza che provoca spese extra!

Ho aggiornato il codice in modo che sia scorrevole.

Con questo codice, quello che faccio è mantenere la vista della mappa delle stesse dimensioni ma invece sposto il punto del centro per compensare l'altezza della vista scorrevole.

Per far funzionare questo codice, è necessario modificare l'impostazione di keithbhunter in modo che il vincolo di fondo di mapView sia completamente bloccato sul fondo della superview (e non su slidingView (in modo che mapView abbia sempre le stesse dimensioni della vista super) . per il resto l'impostazione è la stessa.

enter image description here

Inoltre è possibile personalizzare la quantità di zoom con la variabile maxMetersDistance

Qui sto, sempre al centro l'Eifel torre

enter image description here enter image description here

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; 
    } 

} 
+0

Grazie Juan & Keith! C'è un po 'di nervosismo nella soluzione di Juan che devo capire, ma questo è molto vicino a quello che stavo cercando :) – Aodh