如何修复自定义点注释从重叠中消失?

How to fix custom Point Annotations from disappearing from overlap?

正在尝试显示来自 MapKits 本地搜索的自定义点注释。当注释首次加载到地图上时,所有注释都会显示,但随后重叠的注释会消失。而且它们只会在您放大该区域时重新出现。

许多堆栈解决方案已向用户说明view?.displayPriority = .required。但是由于某些原因,这行代码不起作用。

按下按钮时的本地搜索功能

@IBAction func groceryLocalSearch(_ sender: Any) {
    self.localStoresArray.removeAll()
    self.LocalMapKit.removeAnnotations(self.LocalMapKit.annotations)
    currentLocationBtn.isHidden = false
    localRequest.naturalLanguageQuery = "Grocery"
    //localRequest.region = LocalMapKit.region

    self.localSearchBtn.isEnabled = false

    let search = MKLocalSearch(request: localRequest)

    search.start(completionHandler: {(response, error) in

        if error != nil{
            print("Error occured when searching: \(error!.localizedDescription)")
        } else if response!.mapItems.count == 0 {
            print("There were no results in the search")
        } else {
            print("\(response!.mapItems.count) Results found!")
            for item in response!.mapItems {
                //Add each item to a array to access in table view
                self.localStoresArray.append(item)
                let stores = MKPointAnnotation()
                stores.title = item.name
                stores.coordinate = item.placemark.coordinate
                self.LocalMapKit.addAnnotation(stores)
            }
        }
        self.LocalMapKit.showAnnotations(self.LocalMapKit.annotations, animated: true)
        self.localStoresTableView.reloadData()
    })

查看注释函数

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?{
    guard annotation is MKPointAnnotation else { return nil }

    let identifier = "Annotation"

    var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)

    if annotationView == nil {
        annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
        annotationView?.displayPriority = .required
        //annotationView?.canShowCallout = true
    } else {
        annotationView!.annotation = annotation

    }

    return annotationView
}

我想要这样,当用户进行本地搜索时,它会显示所有注释,无论它们是否彼此靠近,而无需放大。

当前地图视图的图像:

您显然没有为您的地图视图设置 delegate,因为这些注释视图不是 MKPinAnnotationView,而是默认的 MKMarkerAnnotationView。如果您要实现 MKMapViewDelegate 方法,则必须设置地图视图的 delegate(在 IB 中或以编程方式)。

这种消失的行为是因为默认MKMarkerAnnotationView配置为启用集群,但您还没有注册MKMapViewDefaultClusterAnnotationViewReuseIdentifier

因此,如果您真的想要图钉注释视图而不想要集群,请设置您的地图视图 delegate,您的方法应该可以完成您想要的。


我个人建议您通过将注释视图的配置移动到 MKPinAnnotationView subclass:

来减少视图控制器的膨胀
class CustomAnnotationView: MKPinAnnotationView { // or use `MKMarkerAnnotationView` if you want
    override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
        super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
        displayPriority = .required
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

然后,如果您的目标是 iOS 11 及更高版本,在您的 viewDidLoad 中,您可以注册 class,而不必实施 mapView(_:viewFor:) 完全:

mapView.register(CustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)

或者,如果您想适当地享受集群,您可以扩展您的 CustomAnnotationView:

class CustomAnnotationView: MKPinAnnotationView { // or use `MKMarkerAnnotationView` if you want
    static let preferredClusteringIdentifier: String? = Bundle.main.bundleIdentifier! + ".CustomAnnotationView"

    override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
        super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
        clusteringIdentifier = CustomAnnotationView.preferredClusteringIdentifier
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override var annotation: MKAnnotation? {
        didSet {
            clusteringIdentifier = CustomAnnotationView.preferredClusteringIdentifier
        }
    }
}

然后注册您的注释视图和集群注释视图:

mapView.register(CustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
mapView.register(MKMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultClusterAnnotationViewReuseIdentifier)

然后您就可以毫不费力地享受集群。