将地图注释居中到屏幕的上四分之一

Centering a map annotation to the top quarter of the screen

所以我想在单击注释 (Mapbox) 时从图像 1 转到图像 2:

https://i.stack.imgur.com/OFIFa.png

通过在 Mapbox 委托函数之一中调用 mapView.setCenter(),可以很容易地让地图以注释为中心,如下所示:

func mapView(_ mapView: MGLMapView, didSelect annotation: MGLAnnotation) {
    mapView.setCenter(annotation.coordinate, animated: true)
}

显然,这会将注释居中放置在屏幕中间,但我需要注释 'centered' 位于弹出视图上方的区域,这样它仍然可见(理想情况下,它会与 'View' 的顶部和屏幕的顶部边缘等距。

我正在考虑在 setCenter 中设置 zoomLevel,然后缩放到注释以南的特定距离,但这样做的问题是 iOS 设备上的各种屏幕尺寸会使注释居中不同。

我也在想也许我可以在屏幕上进行某种从地图到 CGPoint 的坐标转换,但我真的不确定如何正确地实现它(我只使用过 mapView.convert( CGPoint,toCoordinateFrom: mapView),这在这里没有用)。我不确定如何解决这个问题。任何帮助将不胜感激,无论它只是让我开始一条道路,还是您已经有了更好的解决方案。谢谢!

您可以将地图框的大小调整为该正方形,然后将坐标居中。这意味着该视图将不再在 mapview 上弹出操作,尽管它看起来是。

这可以通过以下方式完成:

(your MKMapView).frame = CGRect(x: , y: , width: , height: )

x 和 y 是 superview(mapview 后面的视图)坐标系中的起始坐标。然后 width 和 height 参数创建一个矩形,这些矩形的尺寸从 x 和 y 开始。小心起点,它有时在左下角,有时在左上角,视情况而定。根据您的实施,您可能还必须修改弹出视图框架。

-如果您的地图始终连接到屏幕顶部,您可以使用

(your MKMapView).frame = CGRect(x: self.view.origin.x, y: self.view.origin.y, width: self.view.frame.width, height: self.view.frame.height/2)

我不使用 MapBox,但如果您可以访问区域的跨度(地图的水平和垂直距离)

您可以从注释的坐标中减去所需的纬度跨度,然后设置地图的中心。

    ///Centers the map region by placing the passed annotation in the center of the I quadrant
    func centerTop(annotation: SpecialAnnot){
        //Find a 4th of the span (The horizontal and vertical span representing the amount of map to display.)
        let latCorrection = region.span.latitudeDelta/4 + region.span.latitudeDelta/8
        
        self.region = MKCoordinateRegion(center: .init(latitude: annotation.coordinate.latitude - latCorrection, longitude: annotation.coordinate.longitude), span: region.span)
    }

这是一些 SwiftUI 代码。

import SwiftUI
import MapKit
class SpecialAnnot: NSObject, MKAnnotation, Identifiable{
    let id: UUID = .init()
    var coordinate: CLLocationCoordinate2D
    init(coordinate: CLLocationCoordinate2D) {
        self.coordinate = coordinate
        super.init()
    }
    
}
struct QuarterCenteredView: View {
    @State var region: MKCoordinateRegion = MKCoordinateRegion()
    
    let annotationCoordinate: [SpecialAnnot] = [SpecialAnnot(coordinate: .init(latitude: 40.748817, longitude: -73.985428))]
    var body: some View {
        VStack{
            Button("center quadrant I", action: {
                centerTop(annotation: annotationCoordinate.first!)
            })
            Map(coordinateRegion: $region, annotationItems: annotationCoordinate, annotationContent: { annot in
                MapAnnotation(coordinate: annot.coordinate, content: {
                    Image(systemName: "mappin").foregroundColor(.red)
                })
            })
                .onAppear(perform: {
                    DispatchQueue.main.async {
                        region = MKCoordinateRegion(center: annotationCoordinate.first!.coordinate, span: region.span)
                    }
                })
        }
    }
    ///Centers the map region by placing the passed annotation in the center of the I quadrant
    func centerTop(annotation: SpecialAnnot){
        //Find a 4th of the span (The horizontal and vertical span representing the amount of map to display.)
        let latCorrection = region.span.latitudeDelta/4 + region.span.latitudeDelta/8
        
        self.region = MKCoordinateRegion(center: .init(latitude: annotation.coordinate.latitude - latCorrection, longitude: annotation.coordinate.longitude), span: region.span)
    }
}

struct QuarterCenteredView_Previews: PreviewProvider {
    static var previews: some View {
        QuarterCenteredView()
    }
}