防止在 MKMapView 中取消选择注释
Preventing annotation deselection in MKMapView
我在我的应用程序中遇到一种情况,我想禁用注解 deselection(除了 selecting 另一个),所以当我点击 的任何地方时不是 注释视图,它应该保留当前selected 注释。如果我点击另一个注释视图,它应该 select 那个和 deselect 另一个。
我希望能找到类似于 MKMapViewDelegate
中的 willDeselectAnnotationView
或 MKAnnotationView
中的 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
}
}
我在我的应用程序中遇到一种情况,我想禁用注解 deselection(除了 selecting 另一个),所以当我点击 的任何地方时不是 注释视图,它应该保留当前selected 注释。如果我点击另一个注释视图,它应该 select 那个和 deselect 另一个。
我希望能找到类似于 MKMapViewDelegate
中的 willDeselectAnnotationView
或 MKAnnotationView
中的 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
}
}