当用户缩小并且注释彼此太靠近时隐藏 MKAnnotations

Posted

技术标签:

【中文标题】当用户缩小并且注释彼此太靠近时隐藏 MKAnnotations【英文标题】:Hide MKAnnotations when user zooms out and annotations are too close to each other 【发布时间】:2013-09-13 06:19:33 【问题描述】:

到目前为止,我已经在某些应用程序中看到了这一点,当用户缩小时,注释会彼此靠近,如果它们太靠近,则会被替换为例如一个“+5”别针或其他东西。

如何做到这一点? 我认为应该在regionDidChangeAnimated 中完成,并在mapview 上检查每个Pin 之间的距离(不是实际距离)。

这是正确的方法吗?如何在 mapview 上获取距离而不是其中的距离(例如,NY 和 SF 之间的距离将始终相同,但如果用户缩小,地图上图钉之间的距离会缩小)

【问题讨论】:

【参考方案1】:

在 WWDC 2017 What's New in MapKit 他们向我们介绍了 ios 11 中的一个新的 annotation clustering API,这使得实现集群变得异常容易。简而言之,为您的注释视图设置一个clusteringIdentifier,它会为您处理所有的集群逻辑。例如

override func viewDidLoad() 
    super.viewDidLoad()

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

并且,在此过程中,不需要 MKMapViewDelegate 方法(尽管如果您想要进一步自定义,显然可以这样做,但如果您对基本 UX 没问题,则默认重用标识符消除了对它的需要。关键是,你必须实现你的注释视图,特别是为你的主注释视图设置clusteringIdentifier,这样集群就会自动发生,例如

class CustomAnnotationView: MKMarkerAnnotationView 

    static let clusteringIdentifier = "ClusterAnnotationView"

    let annotationWidth = 40

    override init(annotation: MKAnnotation?, reuseIdentifier: String?) 
        super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
        clusteringIdentifier = CustomAnnotationView.clusteringIdentifier
        collisionMode = .circle
    

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

    override var annotation: MKAnnotation? 
        willSet 
            clusteringIdentifier = CustomAnnotationView.clusteringIdentifier
            // you can do whatever other update to your `newValue` annotation needed here, if you'd like
        
    

class ClusterAnnotationView: MKAnnotationView 

    override init(annotation: MKAnnotation?, reuseIdentifier: String?) 
        super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
        displayPriority = .defaultHigh
        collisionMode = .circle
    

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

    override var annotation: MKAnnotation? 
        willSet 
            updateImage(for: newValue as? MKClusterAnnotation)
        
    

    private func updateImage(for cluster: MKClusterAnnotation?) 
        guard let cluster = cluster else  image = nil; return 

        let rect = CGRect(origin: .zero, size: CGSize(width: 40, height: 40))
        let renderer = UIGraphicsImageRenderer(size: rect.size)
        image = renderer.image  _ in
            // e.g. circle

            #colorLiteral(red: 0.1215686277, green: 0.01176470611, blue: 0.4235294163, alpha: 1).setFill()
            #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0).setStroke()
            let path = UIBezierPath(arcCenter: rect.center, radius: rect.radius, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
            path.lineWidth = 0.5
            path.fill()
            path.stroke()

            // with count in the center

            let text = "\(cluster.memberAnnotations.count)"
            let attributes: [NSAttributedString.Key: Any] = [
                .foregroundColor: UIColor.white,
                .font: UIFont.boldSystemFont(ofSize: 20)]
            let size = text.size(withAttributes: attributes)
            let textRect = CGRect(origin: CGPoint(x: rect.midX - size.width / 2, y: rect.midY - size.height / 2), size: size)
            text.draw(in: textRect, withAttributes: attributes)
        
    

不再需要我在下面的原始答案中考虑的所有复杂手动聚类。


在 WWDC 2011 Visualizing Information Geographically with MapKit 中,他们展示了一种精确实现此目的的方法(演示的内容大约在视频 18 分钟后开始)。他们采用的概念是将可见地图划分为网格的概念,如果特定网格中有多个注释,他们会删除它们并添加单个“集群”注释。它们说明了您甚至可以如何在视觉上动画化注释进出集群的移动,因此用户可以在放大和缩小时了解正在发生的事情。这是您深入研究的一个很好的起点。

【讨论】:

在 swift 中,我正在使用地图自定义图像,例如比普通图钉更大的圆形阴影作为用户位置。这在用户位置图像下隐藏/重叠了几个引脚,我如何将所有引脚从用户位置带到前面?我为其他引脚尝试了将subview tofront,它不起作用。例如:cutt.ly/ap2pLIv。你能帮帮我吗?

以上是关于当用户缩小并且注释彼此太靠近时隐藏 MKAnnotations的主要内容,如果未能解决你的问题,请参考以下文章

当它们彼此靠近时对点进行分组

当餐厅彼此靠近时,地图看起来人满为患

缩小合并注释

当用户放大 UIScrollView 时如何隐藏某些内容,然后在缩小时显示它?

在 MkMapView 上隐藏、显示注释

自定义 UIToolbar 太靠近 iPhone X 上的主页指示器