You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义MKAnnotationView仅底部响应点击,mapView:didSelect方法无法稳定触发

问题根因

iOS 默认不会将点击事件传递到超出父视图 bounds 范围的子视图区域,你的代码存在两处核心问题导致点击失效:

  1. 你给 containerView 设置了 x: -40, y: -70 的负坐标,而 MKAnnotationView 本身的 bounds 只有 70x70 大小,导致 containerView 90% 以上的区域都在父视图的 bounds 之外,无法响应点击
  2. 所有子视图都开启了 isUserInteractionEnabled = true,会拦截点击事件,导致 MKMapView 的 didSelect 代理无法正常触发

解决方案

调整视图布局逻辑,将所有子视图放在 MKAnnotationView 的 bounds 范围内,通过 centerOffset 属性调整标注相对于坐标点的偏移位置,不要通过给子视图设置负坐标实现偏移效果。


具体代码修改

1. 修改 mapView(_:viewFor:) 方法

删掉手动给 annotationView 赋值 frame 的代码:

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        guard !annotation.isKind(of: MKUserLocation.self) else {
            return nil
        }
        
        var annotationView: MKAnnotationView!
        var annotationIdentifier: String!
        
        if annotation.isKind(of: GroupUserAnnotation.self) {
            annotationIdentifier = "groupUser"
            annotationView = GroupUserAnnotationView(annotation: annotation as! GroupUserAnnotation, reuseIdentifier: annotationIdentifier)
            // 删掉下面这行错误代码
            // annotationView.frame = (annotationView as! GroupUserAnnotationView).containerView.frame
        } else {
            annotationIdentifier = "marker"
            annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
        }
        return annotationView
    }

2. 修改 GroupUserAnnotationView 代码

class GroupUserAnnotationView: MKAnnotationView {
    public lazy var containerView: UIView = {
        // 移除负坐标,origin 改为 0,0
        let view = UIView(frame: CGRect(x: 0, y: 0, width: 70, height: 70))
        view.backgroundColor = .accentColor
        view.layer.cornerRadius = view.frame.width / 2
        // 关闭不必要的用户交互,避免拦截点击
        view.isUserInteractionEnabled = false
        return view
    }()
    
    public lazy var imageView: UIImageView = {
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.image = (annotation as! GroupUserAnnotation).image!
        imageView.clipsToBounds = true
        // 关闭用户交互
        imageView.isUserInteractionEnabled = false
        return imageView
    }()
    
    public lazy var bottomCornerView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = .accentColor
        view.layer.cornerRadius = 4.0
        // 关闭用户交互
        view.isUserInteractionEnabled = false
        return view
    }()
    
    override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
        super.init(annotation: annotation as! GroupUserAnnotation, reuseIdentifier: reuseIdentifier)
        setupView()
        // 新增:设置 annotationView 大小,包含底部尖角的总高度
        bounds = CGRect(x: 0, y: 0, width: 70, height: 74)
        // 新增:设置偏移,让底部尖角对准坐标点
        centerOffset = CGPoint(x: 0, y: -bounds.height / 2)
    }
    
    // 其余原有代码保持不变
}

修改完成后整个标注的所有区域都可以正常响应点击,didSelect 代理会正常触发。

内容的提问来源于stack exchange,提问作者goatofanerd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 12:18:03