如何检测MKAnnotationView/MKMarkerAnnotationView的首次与第二次点击
MKMapView标注二次点击检测实现方案
mapView(_:didSelect:) 回调仅在标注从未选中状态切换到选中状态时触发,已经处于选中状态的标注被重复点击时不会走这个回调,因此无法直接在该方法内靠点击计数判断第二次点击,推荐通过「自定义点击手势+状态标记」的方案实现,兼容性和稳定性最好。
具体实现步骤
1. 给MKAnnotationView扩展状态标记属性
由于系统的MKAnnotationView没有自带记录放大状态的属性,可以通过关联对象给它扩展一个布尔标记,用来记录当前标注是否处于放大状态:
import MapKit import ObjectiveC private var isExpandedKey: UInt8 = 0 extension MKAnnotationView { var isExpanded: Bool { get { return objc_getAssociatedObject(self, &isExpandedKey) as? Bool ?? false } set { objc_setAssociatedObject(self, &isExpandedKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } }
2. 给标注绑定点击手势
在创建/复用标注的mapView(_:viewFor:)代理方法中,给每个标注绑定点击手势,注意复用标注时要移除旧手势避免重复触发:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { // 排除用户位置标注,可按需调整 guard !(annotation is MKUserLocation) else { return nil } let markerView = mapView.dequeueReusableAnnotationView(withIdentifier: "CustomMarker", for: annotation) // 移除已有手势,避免复用导致重复添加 markerView.gestureRecognizers?.removeAll { $0 is UITapGestureRecognizer } let tap = UITapGestureRecognizer(target: self, action: #selector(handleMarkerTap(_:))) tap.cancelsTouchesInView = false markerView.addGestureRecognizer(tap) // 初始状态重置,避免复用错位 markerView.isExpanded = false markerView.transform = .identity return markerView }
3. 实现点击切换尺寸逻辑
在手势响应方法里根据isExpanded状态切换标注尺寸,同时主动同步地图的选中状态,和系统默认交互逻辑对齐:
@objc private func handleMarkerTap(_ gesture: UITapGestureRecognizer) { guard let tappedMarker = gesture.view as? MKAnnotationView, let targetAnnotation = tappedMarker.annotation else { return } if tappedMarker.isExpanded { // 第二次点击:恢复原始尺寸,取消选中 UIView.animate(withDuration: 0.25) { tappedMarker.transform = .identity } tappedMarker.isExpanded = false mapView.deselectAnnotation(targetAnnotation, animated: false) } else { // 可选:点击新标注时,先把其他已经放大的标注恢复原尺寸 mapView.visibleAnnotations?.forEach { ann in if let otherView = mapView.view(for: ann), otherView != tappedMarker, otherView.isExpanded { otherView.isExpanded = false UIView.animate(withDuration: 0.25) { otherView.transform = .identity } } } // 第一次点击:放大标注,设置选中 UIView.animate(withDuration: 0.25) { // 放大比例可按需调整 tappedMarker.transform = CGAffineTransform(scaleX: 1.5, y: 1.5) } tappedMarker.isExpanded = true mapView.selectAnnotation(targetAnnotation, animated: false) } }
效果参考

注意:不要在原来的
didSelect代理方法里重复写放大/选中逻辑,所有尺寸切换逻辑统一放在手势响应方法中处理,避免和系统默认选中逻辑冲突。
内容的提问来源于stack exchange,提问作者Emdetto
相关产品推荐
相关产品推荐

