防止在 MKMapView 中取消选择注释

Preventing annotation deselection in MKMapView

我在我的应用程序中遇到一种情况,我想禁用注解 deselection(除了 selecting 另一个),所以当我点击 的任何地方时不是 注释视图,它应该保留当前selected 注释。如果我点击另一个注释视图,它应该 select 那个和 deselect 另一个。

我希望能找到类似于 MKMapViewDelegate 中的 willDeselectAnnotationViewMKAnnotationView 中的 isDeselected 的内容,但遗憾的是没有这样的东西。我还尝试在 MKMapView 的自定义子类中覆盖 deselectAnnotation,但似乎点击触发 deselect 不会调用该函数。

是否可以在保留 select 能力的同时禁用注解 deselection?谢谢!

我找到方法了!创建一个名为 "allowSelectionChanges" 的布尔值,我现在只是将其作为全局变量。然后使用 MKMapView 的子类,里面有这个覆盖函数:

override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
        return allowSelectionChanges
    } 

只要您想阻止注释选择和取消选择,请将此变量切换为 false。它不会影响用户在地图上移动的能力!


这是一个示例,说明如何使用它来阻止标注在您点击它以与之交互时被取消选择。把它放在你的 MKAnnotationView 子类中:

override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
        let rect = self.bounds
        var isInside = CGRectContainsPoint(rect, point)
        if !isInside {
            for view in self.subviews {
                isInside = CGRectContainsPoint(view.frame, point)
                if isInside {
                    allowSelectionChanges = false
                    return true
                }
            }
            allowSelectionChanges = true
        }

        return false
    }

好吧...我自己遇到了这个问题,虽然@clinton 的回答为我指出了正确的方向,但我想出了一个不需要您的 MKAnnotationView 子类了解 [=12] 的解决方案=]的习惯属性.

这是我为 Swift 3 编写的解决方案:

public class <#CustomMapViewClass#>: MKMapView {

    private var allowSelectionChanges: Bool = true

    public override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return allowSelectionChanges
    }

    public override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        let pointInside = super.point(inside: point, with: event)
        if !pointInside {
            return pointInside
        }

        for annotation in annotations(in: visibleMapRect) where annotation is <#CustomAnnotationViewClass#> {
            guard let view = self.view(for: annotation as! MKAnnotation) else {
                continue
            }
            if view.frame.contains(point) {
                allowSelectionChanges = true
                return true
            }
        }
        allowSelectionChanges = false

        return pointInside
    }

}

我的工作基于@clinton 和@mihai-fratu。他们两个都给出了很好的答案,所以你也应该给他们投票。我想补充的是,如果点击的注释在一个集群中,或者如果它被禁用,那么您仍然会取消选择。这是我尝试修复该问题的代码。

public class <#CustomMapViewClass#>: MKMapView {

    private var allowSelectionChanges: Bool = true

    public override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return allowSelectionChanges
    }

    public override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        let pointInside = super.point(inside: point, with: event)
        if pointInside {
            // Go through all annotations in the visible map rect
            for annotation in annotations(in: visibleMapRect) where annotation is MKAnnotation {
                // get the view of each annotation
                if let view: MKAnnotationView = self.view(for: annotation as! MKAnnotation) {
                    // work with the cluster view if there is one
                    let rootView = view.cluster ?? view
                    // If the frame of this view contains the selected point, then we are an annotation tap. Allow the gesture...
                    if (rootView.frame.contains(point)) {
                        allowSelectionChanges = rootView.isEnabled  // But only if the view is enabled
                        return pointInside
                    }
                }
            }
            // If you did not tap in any valid annotation, disallow the gesture
            allowSelectionChanges = false
        }
        return pointInside
    }
}