问题
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