Preventing annotation deselection in MKMapView

爷,独闯天下 提交于 2020-01-25 02:56:32

问题


I have a situation in my app where I want to disable annotation deselection (other than when selecting another), so when I tap anywhere that is not an annotation view, it should leave the currently selected annotation as is. If I tap on another annotation view, it should select that one and deselect the other.

I was hoping to find something along the lines of a willDeselectAnnotationView in the MKMapViewDelegate or an isDeselected in MKAnnotationView, but there's unfortunately no such thing. I also tried overriding deselectAnnotation in a custom subclass of MKMapView, but it seems the tap triggered deselect doesn't invoke that function.

Is it possible to disable annotation deselection while preserving the ability to select? Thanks!


回答1:


I've found a way to do it! Make a boolean named something like "allowSelectionChanges", which I just have as global for now. Then use a subclass of MKMapView with this overriden function inside:

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

Switch this variable to false whenever you want to prevent annotation selection and deselection. It won't affect the user's ability to move around the map!


Here's an example of how this can be used to stop a callout from getting deselected when you tap on it to interact with it. Put this in your MKAnnotationView subclass:

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
    }



回答2:


Ok... I had this issue myself and while @clinton's answer pointed me in the right direction I came up with a solution that doesn't require your MKAnnotationView subclass to know about the mapView's custom property.

Here's my solution written for 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
    }

}



回答3:


I'm basing my work off of @clinton and @mihai-fratu. Both of them gave very good answers so you should up-vote them as well. What I want to add is that if the tapped annotation is in a cluster, or if it is disabled, then you will still get the deselection happening. This is my code to attempt to fix that.

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
    }
}


来源:https://stackoverflow.com/questions/34835499/preventing-annotation-deselection-in-mkmapview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!