SwiftUI 地图显示注解

Posted

技术标签:

【中文标题】SwiftUI 地图显示注解【英文标题】:SwiftUI Map Display Annotations 【发布时间】:2020-06-23 20:15:08 【问题描述】:

我决定从将 MKMapView 包装成 UIViewRepresentable 切换到 SwiftUI 中的新 Map()

我能够在Map() 中正确显示MKMapRect,但我无法在那里显示两个MKPointAnnotation。我在这些注释之间的路线也没有显示

要求我提供RandomAccessCollection(Identifiable) -> MapAnnotationProtocol>,但我不知道该放什么。

知道我应该在(Identifiable) -> MapAnnotationProtocol 中输入什么吗?

import SwiftUI
import MapKit

extension MKPointAnnotation: Identifiable  

struct ItemView: View 
    @ObservedObject var itemViewModel: ItemViewModel
    @State var coll = [MKPointAnnotation]()
    
    func onAppear() 
        let requestAnnotation = MKPointAnnotation()
        requestAnnotation.coordinate = CLLocationCoordinate2D(latitude: 46.2004781, longitude: 6.1346497)
        requestAnnotation.title = "Package"
        
        let destinationAnnotation = MKPointAnnotation()
        destinationAnnotation.coordinate = CLLocationCoordinate2D(latitude: 47.1420446, longitude: 9.5204032)
        destinationAnnotation.title = "Destination"
        
        coll.append(requestAnnotation)
        coll.append(destinationAnnotation)
    
    
    var body: some View 
        VStack 
            if let mapRect = itemViewModel.route?.polyline.boundingMapRect 
                Map(mapRect: .constant(mapRect), annotationItems: coll)  point in
                  MapAnnotation(coordinate: point.coordinate) 
                      Text(point.title ?? "")
                  
                
            
        
        .onAppear(perform: self.onAppear)
    
    

【问题讨论】:

【参考方案1】:

您不再需要MKPointAnnotation。目前,在 Xcode 12.0 Beta 中,SwiftUI 提供了三个结构来满足MapAnnotationProtocol

MapAnnotation MapMarker MapPin

RandomAccessCollection 应该是采用Identifiable 的任何对象集合(数组可以)。这些在 Map 初始化器的最后一个参数中用作块的参数。

Map(coordinateRegion: $container.region, 
    annotationItems: container.annotationLocations)  
        (location) -> MapPin in
            MapPin(coordinate: location.coordinate)
    )

【讨论】:

路由呢?是否可以在 SwiftUI 中实现? 我不知道。希望他们发布有关新地图功能的视频,但我想我们还没有得到。我们将看看它是否会在接下来的几个测试版中得到充实...... 你能用 MapAnnotation 做一个例子吗?我还需要显示一些文本,这就是我需要 MapAnnotation 的原因【参考方案2】:

在我看来,MapAnnotation 要求您实现将在地图上呈现的整个视图,因此如果您需要红色图钉和一些文本,则必须自己创建该图钉(例如,作为带有 SF 符号的图像实例)。当然,它看起来不如MapMarker 的图钉那么好,但至少它是一个开始。

Map(coordinateRegion: .constant(mapRect), annotationItems: coll)  annotationItem in
  MapAnnotation(coordinate: annotationItem.coordinate) 
    VStack 
      Group 
        Image(systemName: "mappin.circle.fill")
          .resizable()
          .frame(width: 30.0, height: 30.0)
        Circle()
          .frame(width: 8.0, height: 8.0)
      
      .foregroundColor(.red)
      Text(annotationItem.title)
    
  

【讨论】:

【参考方案3】:

应该如下所示(由于提供的快照中缺少依赖关系,未测试)

Map(mapRect: .constant(mapRect), annotationItems: coll)  point in
   MapAnnotation(coordinate: point.coordinate) 
    Text(point.title ?? "")
   

【讨论】:

代码编译正常,但我看不到红色注释,知道我在这里做错了什么吗? 我还用硬编码坐标更新了我的问题以进行测试。【参考方案4】:

对于任何搜索 SwiftUI MKPolyline 路线的人

    struct MapView: View 
        
        @ObservedObject var viewModel: MapViewModel
        
        var body: some View 
            VStack(spacing: 0) 
                Text("Status")
                    .padding()
                MapViewRepresentable(exampleRoute: viewModel.exampleRoute)
                Button("Button", action:  )
                    .padding()
            
        
        
    
    
    
    struct MapView_Previews: PreviewProvider 
        static var previews: some View 
            MapView(viewModel: MapViewModel())
        
    
    
    
    struct MapViewRepresentable: UIViewRepresentable 
        
        private let initialRegion = CoordinateRegion.initial
        
        let exampleRoute: MKPolyline
        
        func makeCoordinator() -> Coordinator 
            return Coordinator(self)
        
        
        func makeUIView(context: UIViewRepresentableContext<MapViewRepresentable>) -> MKMapView 
            let mapView = MKMapView()
            mapView.delegate = context.coordinator
            mapView.setRegion(initialRegion, animated: false)
            mapView.showsUserLocation = true
            mapView.addOverlay(exampleRoute)
            return mapView
        
    
        func updateUIView(_ view: MKMapView,
                          context: UIViewRepresentableContext<MapViewRepresentable>) 
    
        
        
        class Coordinator: NSObject, MKMapViewDelegate 
            let parent: MapViewRepresentable
            init(_ mapView: MapViewRepresentable) 
                parent = mapView
            
            func mapView(_ mapView: MKMapView,
                         rendererFor overlay: MKOverlay) -> MKOverlayRenderer 
                let polylineRenderer: MKPolylineRenderer = MKPolylineRenderer(overlay: overlay)
                polylineRenderer.lineWidth = 3
                polylineRenderer.strokeColor = UIColor.red
                return polylineRenderer
            
        
        
    


class MapViewModel: ObservableObject 
    
    @Published private(set) var exampleRoute = createPolylines()
    
    static func createPolylines() -> MKPolyline 
        var coordinates1 = createExampleRoute()
        return MKPolyline(coordinates: &coordinates1, count: coordinates1.count)
    
    
    static func createExampleRoute() -> [CLLocationCoordinate2D] 
        return [CLLocationCoordinate2D(latitude: 60.608905, longitude: 39.814428),
                CLLocationCoordinate2D(latitude: 60.609073, longitude: 39.812000),
                CLLocationCoordinate2D(latitude: 60.610429, longitude: 39.812071)]
    
    



struct CoordinateRegion 
    static let initial = MKCoordinateRegion(center: CLLocationManager().location?.coordinate
                                                    ?? CLLocationCoordinate2D(latitude: 60.608905,
                                                                              longitude: 39.814428),
                                            span: MKCoordinateSpan(latitudeDelta: 0.05,
                                                                   longitudeDelta: 0.05))
    func getCurrentLocation() -> CLLocationCoordinate2D 
        return CLLocationManager().location!.coordinate
    
    

【讨论】:

以上是关于SwiftUI 地图显示注解的主要内容,如果未能解决你的问题,请参考以下文章

为啥 SwiftUI 不能正确显示两个视图?

SwiftUI 地图扩展添加 MKPolylineRenderer

SwiftUI:在地图视图上更改地图类型?

Swiftui + 核心位置:地图无法以用户为中心

如何在 SwiftUI 的新地图视图中制作可点击的图钉?

SwiftUI 中的地图和滚动视图