【问题标题】:How to generate annotations on a certain zoom and only those close to where user zoomed in?如何在某个缩放上生成注释,并且仅在用户放大的位置附近生成注释?
【发布时间】:2022-11-24 03:41:51
【问题描述】:

我的应用程序请求 JSON 数据(纬度、经度和有关某个地方的其他信息),然后以可点击注释的形式将它们显示在地图上。我收到了大约 30,000 个,所以你可以想象,该应用程序可能会有点“滞后”。

我认为最适合该应用程序的解决方案是仅在特定缩放级别上显示这些注释(例如,当用户缩放以便一次只能看到一个城市时,注释将显示)。由于它们很多,显示所有 30,000 个可能会使应用程序崩溃,这就是为什么我也旨在仅显示靠近用户放大位置的那些。

下面的代码立即显示所有缩放级别的所有注释。有没有办法让它适应我上面描述的事情?

struct Map: UIViewRepresentable {
    
    @EnvironmentObject var model: ContentModel
    @ObservedObject var data = FetchData()
    
    var locations:[MKPointAnnotation] {
        
        var annotations = [MKPointAnnotation]()
        
        // Loop through all places
        for place in data.dataList {
            
            // If the place does have lat and long, create an annotation
            if let lat = place.latitude, let long = place.longitude { 
                
                // Create an annotation
                let a = MKPointAnnotation()
                a.coordinate = CLLocationCoordinate2D(latitude: Double(lat)!, longitude: Double(long)!)
                a.title = place.address ?? ""
                
                annotations.append(a)
                
            }
        }
        
        return annotations
        
    }
    
    func makeUIView(context: Context) -> MKMapView {
        
        let mapView = MKMapView()
        mapView.delegate = context.coordinator
        
        // Show user on the map
        mapView.showsUserLocation = true
        mapView.userTrackingMode = .followWithHeading
        
        return mapView
        
    }
    
    func updateUIView(_ uiView: MKMapView, context: Context) {
        
        // Remove all annotations
        uiView.removeAnnotations(uiView.annotations)
        
        // HERE'S WHERE I SHOW THE ANNOTATIONS
        uiView.showAnnotations(self.locations, animated: true)
        
    }
    
    static func dismantleUIView(_ uiView: MKMapView, coordinator: ()) {
        
        uiView.removeAnnotations(uiView.annotations)
        
    }
    
    
    // MARK: Coordinator Class
    
    func makeCoordinator() -> Coordinator {
        
        return Coordinator(map: self)
        
    }
    
    class Coordinator: NSObject, MKMapViewDelegate {
        
        var map: Map
        
        init(map: Map) {
            
            self.map = map
            
        }
        
        func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
            
            // Don't treat user as an annotation
            if annotation is MKUserLocation {

                return nil

            }
            
            // Check for reusable annotations
            var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: Constants.annotationReusedId)
            
            // If none found, create a new one
            if annotationView == nil {
                
                annotationView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: Constants.annotationReusedId)
                
                annotationView!.canShowCallout = true
                annotationView!.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
                
            } else {
                
                // Carry on with reusable annotation
                annotationView!.annotation = annotation
                
            }
            
            return annotationView
            
        }
    }
}

一段时间以来一直在寻找答案,但没有发现任何有效的方法。我想象有一种方法可以获得可见的地图矩形,然后在地图结构中对其进行条件处理,但不知道该怎么做。感谢您阅读到这里!

【问题讨论】:

    标签: swiftui mapkit mapkitannotation


    【解决方案1】:

    您的代表可以实现 mapView(_:regionDidChangeAnimated:),以便在用户完成更改地图可见区域的手势时收到通知。它可以实现 mapViewDidChangeVisibleRegion(_:) 以在手势发生时得到通知。

    您可以通过询问其 region 属性来获取地图的可见区域。关于缩放级别,region 文档是这样说的:

    该区域包括地图居中的纬度和经度点以及要显示的坐标范围。跨度值为地图提供隐式缩放值。显示区域越大,缩放量越小。同样,显示区域越小,缩放量越大。

    updateUIView 方法会在每次 SwiftUI 调用它时重新计算 locations 数组(因为 locations 是一个计算属性)。您应该检查 SwiftUI 调用 updateUIView 的频率,并决定是否需要缓存 locations 数组。

    如果您想有效地找到可见区域中的位置,请尝试将位置存储在quadtree 中。

    【讨论】:

    • 谢谢!我在明智地实施该代码时遇到了一些麻烦,您能帮我看看它的外观吗?
    【解决方案2】:

    终于想通了...

    Coordinator 类可以实现 mapView(_:regionDidChangeAnimated:)(正如@rob mayoff 所说),它在用户完成更改地图可见区域的手势后被调用。发生这种情况时,地图上的注释及其数组会更新。看起来像这样...

    func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
                
       if mapView.region.span.latitudeDelta < <Double that represents zoom> && mapView.region.span.longitudeDelta < <Double that represents zoom> {
                        
            mapView.removeAnnotations(mapView.annotations)
            mapView.addAnnotations(map.getLocations(center: mapView.region.center))
                        
        }
    }
    

    ... &lt; &gt; 中的短语(if 语句中缺少双精度)将替换为您自己的代码(双精度越大,查看注释所需的缩放比例越小)。注释数组由Map结构中定义的函数更新,看起来像这样……

    func getLocations(center: CLLocationCoordinate2D) -> [MKPointAnnotation] {
        
        var annotations = [MKPointAnnotation]()
        let annotationSpanIndex: Double = model.latlongDelta * 10 * 0.035
        
        // Loop through all places
        for place in data.dataList {
            
            // If the place does have lat and long, create an annotation
            if let lat = place.latitude, let long = place.longitude {
                
                // Create annotations only for places within a certain region
                if Double(lat)! >= center.latitude - annotationSpanIndex && Double(lat)! <= center.latitude + annotationSpanIndex && Double(long)! >= center.longitude - annotationSpanIndex && Double(long)! <= center.longitude + annotationSpanIndex {
                    
                    // Create an annotation
                    let a = MKPointAnnotation()
                    a.coordinate = CLLocationCoordinate2D(latitude: Double(lat)!, longitude: Double(long)!)
                    a.title = place.adresa ?? ""
                    
                    annotations.append(a)
                }
                
            }
        }
        
        return annotations
        
    }
    

    ...其中 annotationSpanIndex 确定将在中心点周围的区域中显示多大的注释(索引越大,区域越大)。理想情况下,该区域应略大于显示注释的缩放比例。

    【讨论】:

      猜你喜欢
      • 2010-12-08
      • 1970-01-01
      • 1970-01-01
      • 2013-08-01
      • 1970-01-01
      • 2015-05-29
      • 2021-12-04
      • 2014-02-14
      相关资源
      最近更新 更多