为啥还调用 calloutAccessoryControlTapped 来点击注释视图?
Posted
技术标签:
【中文标题】为啥还调用 calloutAccessoryControlTapped 来点击注释视图?【英文标题】:Why calloutAccessoryControlTapped is called for tap on annotation view also?为什么还调用 calloutAccessoryControlTapped 来点击注释视图? 【发布时间】:2016-04-05 17:07:22 【问题描述】:我的视图控制器上有一个地图,但我不知道为什么,但是当我点击注释视图时也会调用委托 calloutAccessoryControlTapped
,而不仅仅是在我点击详细信息关闭时 .那么为什么会有这种行为呢?
import UIKit
import MapKit
extension MapVC: MKMapViewDelegate, CLLocationManagerDelegate
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl)
...
【问题讨论】:
【参考方案1】:根据 Apple 开发者文档:
附件视图包含自定义内容并位于 注释标题文本的一侧。如果您指定的视图是 UIControl 类的后代,地图视图将此方法作为 方便用户点击您的视图。你可以使用这个方法 响应点击并执行与该点击相关的任何操作 控制。例如,如果您的控件显示附加信息 关于注释,您可以使用此方法呈现模态 包含该信息的面板。
如果您的自定义附件视图不是 UIControl 的后代 类,地图视图不调用该方法。
那么你的附件视图是从 UIControl 继承的吗?
参考: https://developer.apple.com/library/ios/documentation/MapKit/Reference/MKMapViewDelegate_Protocol/#//apple_ref/occ/intfm/MKMapViewDelegate/mapView:annotationView:calloutAccessoryControlTapped:
【讨论】:
对不起,但我看不出重点,文档还说:告诉代表用户点击了注释视图的附件按钮之一。因此,我希望仅针对按钮上的点击事件调用委托,而不是针对整个注释视图。 它说:“您指定的视图是 UIControl 类的后代,每当用户点击您的视图时,地图视图都会调用此方法以方便您。”那么你的附件视图是从 UIControl 继承的吗?【参考方案2】:Massimo Polimeni 似乎是正确的。 rightCalloutAccessoryView 似乎有问题,但 leftCalloutAccessoryView 没有问题。
下面的代码(带有leftCalloutAccessoryView)按预期工作。如果您点击左侧附件,它会打印“已选择左侧附件”。如果您点击标注标题,它不会打印任何内容。
如果您使用 rightCalloutAccessoryView(在下方注释掉)并点击正确的附件,它会打印“选择了正确的附件”。 如果您点击标注标题,它还会打印“选择了正确的配件”。这似乎不正确。
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate
@IBOutlet weak var mapView: MKMapView!
override func viewDidLoad()
super.viewDidLoad()
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2D(latitude: 50.29, longitude: -107.79)
annotation.title = "Swift Current"
mapView.addAnnotation(annotation)
mapView.mapType = .standard
mapView.delegate = self
mapView.region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: annotation.coordinate.latitude,
longitude: annotation.coordinate.longitude),
span: MKCoordinateSpan(latitudeDelta: 1.0, longitudeDelta: 1.0)
)
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
let reuseId = "Annotation"
var view = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
if view == nil
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
view?.canShowCallout = true
view?.leftCalloutAccessoryView = UIButton(type: .detailDisclosure)
//view?.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
else
view?.annotation = annotation
return view
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl)
if control == view.leftCalloutAccessoryView
print("left accessory selected")
else if control == view.rightCalloutAccessoryView
print("right accessory selected")
【讨论】:
【参考方案3】:这取决于您在rightCalloutAccessoryView
上设置的按钮类型。例如。如果你使用:
[UIButton buttonWithType:UIButtonTypeDetailDisclosure];
然后点击标注和点击按钮都会导致calloutAccessoryControlTapped
被按钮调用。但如果你使用:
[UIButton systemButtonWithImage:[UIImage systemImageNamed:@"info.circle"] target:nil action:nil];
那么只有点击按钮才能工作,点击标注将被禁用。
如果您有一个自定义按钮并且想要第一个行为,那么您可以创建一个按钮子类并执行以下操作:
@interface UIButton2 : UIButton
@end
@implementation UIButton2
- (id)_mapkit_accessoryControlToExtendWithCallout
return self;
@end
这个私有方法是它决定按钮是否也应该用于点击标注的方式(使用Hopper 了解这一点)。默认实现检查self.buttonType
来决定。
更明智的方法是从披露按钮开始并更改其图像,例如
UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
UIImage *image = [UIImage systemImageNamed:@"chevron.right" withConfiguration:[UIImageSymbolConfiguration configurationWithScale:UIImageSymbolScaleSmall];
[button setImage:image forState:UIControlStateNormal];
很多这种奇怪的行为很可能与自 iOS 6 以来标注按钮工作方式的变化有关。
【讨论】:
以上是关于为啥还调用 calloutAccessoryControlTapped 来点击注释视图?的主要内容,如果未能解决你的问题,请参考以下文章