如何偏移 MKMapView 以将坐标放在指定点下

How to offset MKMapView to put coordinates under specified point

我有两个视图控制器。一是允许用户输入自己目击的事物:

另一个是 UITableViewController,允许他们查看他们提交的目击事件:

我想要的是让用户能够在第 2 个 VC 中单击他们的目击,并用相关详细信息填充第 1 个 VC。我使用 :

为 textFields 工作
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    
    let pvc = self.navigationController?.previousViewController() as! SubmitSightingVC
    let sighting = sightingsArray[indexPath.row]
    pvc.titleTextField.text = sighting["title"] as! String?
    pvc.locationTextField.text = sighting["location"] as! String?
    pvc.dateTextField.text = sighting["date"] as! String?
    pvc.descriptionTextView.text = sighting["sightingDesc"] as! String?
    
    let pinArray = ["1", "2", "3", "4", "5"]
    let pinTextArray = ["1text", "2text", "3text", "4text", "5text"]
    var pinImageArray = [#imageLiteral(resourceName: "1"), #imageLiteral(resourceName: "2"), #imageLiteral(resourceName: "3"), #imageLiteral(resourceName: "4"), #imageLiteral(resourceName: "5")]
    let pinIconString = sighting["pinIcon"] as! String
    let index = pinArray.index(of: pinIconString)
    
    pvc.pinImageView.image = pinImageArray[index!]
    pvc.pinTextField.text = pinTextArray[index!]
    

    // Bit I'm struggling with:
    var coordinates = CLLocationCoordinate2D(latitude: sighting["latitude"] as! Double, longitude: sighting["longitude"] as! Double)
    pvc.mapView.centerCoordinate = coordinates
    
    self.navigationController!.popViewController(animated: true)
    
}

问题在于,由于地图的中心位于模糊视图的后面,因此发生了偏移。地图上的图钉不是实际图钉,而是 UIImage (pinImageView)。如何移动地图,使坐标位于此 pinImage 下方,而不是位于 mapView 的中心?

如上所述,您可以使用 MKMapCamera 来定位地图的视图,或者您也可以使用 setVisibleMapRect 并添加一些填充来定位地图,如下所示:

self.mapView.setVisibleMapRect(self.mapView.visibleMapRect, edgePadding: UIEdgeInsetsMake(200.0, 0.0, 0.0, 0.0), animated: true)

这将使中心在顶部偏移 200 个屏幕像素。

来自@rmp 的优秀回答,大意是

self.map.setVisibleMapRect(self.map.visibleMapRect,
 edgePadding: UIEdgeInsets(top: -200, left: 0, bottom: 0, right: 0),
 animated: true)

将其“向上移动 200”。 但是请注意,算术运算并不完全正确。

要向上移动“框”,您必须负向插入顶部,和正向插入底部。上面的代码会拉伸和缩放框(中心会向上移动,但会向上移动一个小于 200 的随机高度)。

所以你要做的是:

let UP = 170 // move it up 170
let LEFT = 50 // move it left 50

self.map.setVisibleMapRect(self.map.visibleMapRect,
 edgePadding: UIEdgeInsets(top: -UP, left: -LEFT, bottom: UP, right: LEFT),
 animated: true)

那行得通。

这是在地图上获取点的完整公式,可能是城镇或房屋 coords

1. 很好地居中,不管当前相机位置、角度、缩放等,然后

2. 将它移动,比方说向上,到屏幕上的一个精确点(以允许输入显示或其他)

let coords = .. the coords of the town, house etc
// for example, if you let someone tap on the map, something like...
let coords = map.convert(g.location(in: map), toCoordinateFrom: map)

// we'll need the W/H of the map on the device:

let W = self.map.bounds.width
let H = self.map.bounds.height

// here's the formula to tidily and safely move/zoom
// to center a coords on the screen
let thatRegion = MKCoordinateRegion(
    center: coords,
    latitudinalMeters: 5000 * Double((H/W)),
    longitudinalMeters: 5000)

MKMapView.animate(withDuration: 2, animations: { [weak self] in

    self?.map.region = thatRegion

}, completion: {completed in
    print("part 1 done")

    // so now the coords is centered. but we want to move it
    // so that we can see something else we're adding to the
    // screen on top, such as an input display

..所以这是第一部分。

现在您想继续为移动设置动画以将其从您的用户体验中移开:

    MKMapView.animate(withDuration: 2, animations: { [weak self] in
        guard let self = self else { return }

        // in this example, we'll move the point,
        // to the top-left of the screen, just below the notch:

        let UP = H/2 - 20
        let LEFT = W/4

        // here's the exact formula for moving
        // the center of the map a certain amount UP/LEFT:

        self.map.setVisibleMapRect(self.map.visibleMapRect,
           edgePadding: UIEdgeInsets(
             top: -UP, left: -LEFT, bottom: UP, right: LEFT),
           animated: true)

    }, completion: {completed in
        print("part 2 done")
    })

})

总会做到的。

此外,不幸的是,MapKit 天生就草率。简单地说,不可能将地理点绝对定位在屏幕中央;总会有一些变化。 (以一种或另一种方式说奇数个像素。)这就是 MapKit 的工作方式。此外,如果纹理数据仍在加载,动画(例如上面的两个)可能会被丢弃。