iosswiftmapkituigesturerecognizermkannotation

Unable to Consistently get mapViewdidSelectView function called on a custom MKAnnotationView


When creating a custom MKAnnotationView, called GroupUserAnnotationView, it is only registering the tapping on the bottom part of the annotation, but not the top. I've tried to add a UITapGestureRecognizer to the annotation view, but it did not work.

Creating the annotation view:

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
    }

The GroupUserAnnotationView:


class GroupUserAnnotation: MKPointAnnotation {
    var email: String!
    var image: UIImage!
}

class GroupUserAnnotationView: MKAnnotationView {
    public lazy var containerView: UIView = {
        let view = UIView(frame: CGRect(x: -40, y: -70, width: 70, height: 70))
        view.backgroundColor = .accentColor
        view.layer.cornerRadius = view.frame.width / 2
        view.isUserInteractionEnabled = true
        
        return view
    }()
    
    public lazy var imageView: UIImageView = {
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.image = (annotation as! GroupUserAnnotation).image!
        imageView.clipsToBounds = true
        imageView.isUserInteractionEnabled = true
        return imageView
    }()
    
    public lazy var bottomCornerView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = .accentColor
        view.layer.cornerRadius = 4.0
        view.isUserInteractionEnabled = true
        return view
    }()
    
    // MARK: Initialization
    override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
        super.init(annotation: annotation as! GroupUserAnnotation, reuseIdentifier: reuseIdentifier)
        setupView()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    public func setupView() {
        subviews.forEach({ $0.removeFromSuperview() })
        
        containerView.addSubview(bottomCornerView)
        bottomCornerView.topAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -20.0).isActive = true
        bottomCornerView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor, constant: 2).isActive = true
        bottomCornerView.widthAnchor.constraint(equalToConstant: 24).isActive = true
        bottomCornerView.heightAnchor.constraint(equalToConstant: 24).isActive = true
        
        let angle = (39.0 * CGFloat.pi) / 180
        let transform = CGAffineTransform(rotationAngle: angle)
        bottomCornerView.transform = transform
        
        addSubview(containerView)
        containerView.addSubview(imageView)
        imageView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 2.0).isActive = true
        imageView.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 2.0).isActive = true
        imageView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -2.0).isActive = true
        imageView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -2.0).isActive = true
        
        imageView.layer.cornerRadius = (containerView.frame.size.width - 1) / 2
        
    }

And again, only the bottom part of the annotation is actually registering (which means that I have properly implemented the mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) delegate function.

Any help would be appreciated.

Thanks!


Solution

  • It is even worse: the tap is recognised by the map behind your UIView and causes unintended actions.

    The workaround that works for me is using enabled UIControls instead of UIViews.

    This can be a UIButtons that you use directly as buttons, or an invisible enabled large button in the background and UIViews on top.

    The big invisible UIButton in the background has the task of preventing taps going through to the map.

    Use smaller visible buttons on top for normal user interaction, if needed.