Как сохранить пин-код и карту в центре над движущимся наложением в MKMapView
Как я могу держать булавку по центру на карте, пока я перемещаю (с помощью Панорамирования) другой вид по вертикали над картой так, чтобы булавка оставалась над оверлеем (не фактическим оверлеем MapKit).
Смотрите прикрепленные скриншоты для первого и конечного состояний.
У меня есть CGRect пространства между оверлеем и верхней частью экрана, когда пользователь перемещается вверх / вниз. Однако то, как я использую это, чтобы переместить карту и закрепить ее, одновременно увеличивая масштаб карты, когда пользователь перемещается вверх... и снова уменьшая масштаб, когда пользователь перемещается вниз, до сих пор ускользало от меня.
Я пробовал разные подходы, от попытки отрегулировать видимый прямоугольник до настройки рамки вида карты. Ответ может заключаться в некотором обмане MKMapRect / Region.
(Значок руки от Freepik CC BY 3.0)
2 ответа
На самом деле код keithbhunter медленный, потому что помимо обновления региона быстрее, чем он может его загрузить, карта также изменяет высоту, что приводит к дополнительным накладным расходам!
Я обновил код, чтобы он работал гладко.
С помощью этого кода я сохраняю вид карты того же размера, но вместо этого я перемещаю точку центра, чтобы компенсировать высоту скользящего вида.
Чтобы этот код работал, вы должны изменить настройку keithbhunter так, чтобы нижнее ограничение mapView было полностью прикреплено к основанию суперпредставления (а не к slideView (чтобы размер mapView всегда был таким же, как у суперпредставления). В остальном установка такая же.
Также можно настроить величину увеличения с помощью переменной maxMetersDistance
Здесь я всегда на Эйфелевой башне
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;
}
}
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()
}
}
Чтобы настроить виды, поместите вид карты и UIView
на ваш взгляд контроллер. Используйте autolayout, чтобы прикрепить левую, верхнюю и правую стороны вида карты к суперпредставлению. Затем прикрепите нижнюю часть вида карты к верхней части UIView
, Затем прикрепите левую, нижнюю и правую стороны UIView
к суперпредставлению. Наконец, установите ограничение высоты на UIView
к тому, что вы хотите инициализировать. Это значение высоты будет изменено, когда пользователь перетаскивает вид. Это позволяет UIView
расти, как нам угодно, и одновременно успокаивать автопокрытие.
Добавить @IBOutlet
к вашему контроллеру для просмотра карты, UIView
и UIView
ограничение по высоте, как в коде выше. regionDistance
свойство это то, что делает магию масштабирования здесь. Это экспоненциальное уравнение (которое я сделал случайным образом), которое будет вычислять регион для большего или меньшего размера на основе высоты вида карты. reloadMap()
использует это, чтобы обновить масштаб карты. Связать все это вместе UIPanGestureRecognizer
на UIView
что и контролирует UIView
высота, вызывая масштабирование на карте.
Ловушка: это заставляет карту обновлять регион быстрее, чем она может загружать регион, что делает ее очень нервной. Наверное, есть способы обойти это. Будьте креативны.
Координата, которую я использовал в этом примере, является штаб-квартирой Apple.