swift 如何在MKMapView中保持大头针和标测图在移动覆盖图上方居中

rmbxnbpk  于 2023-03-16  发布在  Swift
关注(0)|答案(2)|浏览(205)

当我在Map上垂直移动(通过平移手势)另一个视图时,如何使大头针保持在Map中心,以便大头针保持在覆盖图上方(而不是实际的MapKit覆盖图)。
第一个和最后一个状态见随附的屏幕截图。
我已经得到了用户上下平移时覆盖层和屏幕顶部之间的空间的CGRect。然而,我如何使用它来移动Map和固定,同时在用户向上平移时放大Map......以及在用户向下平移时再次缩小,到目前为止我还不知道。
我尝试了不同的方法,从试图调整可见矩形到调整Map视图的框架。答案可能在于一些MKMapRect / Region的诡计。

(Hand图标按Freepik CC按3.0)

kse8i1jr

kse8i1jr1#

实际上,keithbhunter的代码很慢,因为除了更新区域的速度比加载速度快之外,Map还会改变高度,这会导致额外的开销!
我更新了代码,使其运行顺畅。
使用这段代码,我所做的是保持Map视图的大小不变,但我移动了中心点,以补偿滑动视图的高度。
要使这段代码正常工作,必须修改keithbhunter的设置,使mapView的底部约束完全固定在超级视图的底部(而不是滑动视图的底部)(使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;
    }

}
w46czmvw

w46czmvw2#

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()
    }

}

要设置视图,请将Map视图和UIView放置在视图控制器中。使用自动布局将Map视图的左侧、顶部和右侧固定到超级视图。然后将Map视图的底部固定到UIView的顶部。接下来,将UIView的左侧、底部和右侧固定到超级视图。最后,在UIView上设置一个高度限制,你可以将它初始化为任意值。这个高度值将随着用户拖动视图而改变。这允许UIView按照我们的意愿增长,同时满足自动布局。
添加一个@IBOutlet到你的视图控制器,用于Map视图,UIViewUIView的高度约束,就像上面的代码一样,regionDistance属性就是这里的缩放魔术,它是一个指数方程(这是我随机创建的),它将根据Map视图的高度计算区域的大小。reloadMap()使用这个来更新Map的缩放。把这一切联系在一起的是UIView上的UIPanGestureRecognizer,这是控制UIView高度的东西,导致Map上的缩放动作。

**缺点:**这会迫使Map更新区域的速度比加载区域的速度快,使Map看起来很不稳定。可能有办法解决这个问题。发挥创造力。

我在示例中使用的坐标是苹果总部。

相关问题