Link MKOverlay and MKAnnotation in MapKit

90 Views Asked by At

I have two MKCircle overlays rendered with a MKCircleRenderer and another custom one. At the bottom of the rendered circles, I want to show a custom view (containing a label and text) which are independent from the zoom level, in other words, they have to be always visible in the map. For this reason, I've created a custom MKAnnnotationView which works great for this. I'd like to move the annotation to the bottom-center of the circle overlay, so that overlay and annotation look like a single element on the map.

This is the final result I want to obtain

Annotation View Class:

class MyAnnotationView: MKAnnotationView {
static var identifier = "MyAnnotationView"

init(
    annotation: GlueAnnotation?,
    reuseIdentifier: String?
) {
    super.init(
        annotation: annotation,
        reuseIdentifier: reuseIdentifier
    )
    guard let annotation = annotation else { return }
    let annotationFrame = CGRect(x: 0, y: 0, width: 125, height: 30)
    self.frame = annotationFrame
    self.backgroundColor = .clear
    let image = UIImageView(frame: annotationFrame.offsetBy(dx: 6, dy: 0)).with {
        $0.image = annotation.style.image.uiKit
        $0.contentMode = .left
    }
    self.addSubview(image)
    
    guard let title = annotation.title else { return }
    
    let label = UILabel(frame: annotationFrame.offsetBy(dx: 32, dy: 4)).with {
        $0.font = Font(style: .subheadline, emphasis: .bold).uiKit
        $0.textColor = BackgroundColor.primary.uiKit
        $0.textAlignment = .center
        $0.text = title
        $0.sizeToFit()
    }
    self.addSubview(label)
}

@available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) not implemented!")
}

override func draw(_ rect: CGRect) {
    guard let annotation = annotation as? GlueAnnotation else { return }
    guard let context = UIGraphicsGetCurrentContext() else { return }
    
    context.beginPath()
    context.move(to: CGPoint(x: rect.minX, y: rect.minY))
    context.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
    context.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
    context.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
    context.closePath()
    
    let color = annotation.style.color.uiKit
    color.set()
    context.fillPath()
}

}

Overlay View Class

public class InvertedCircleOverlayRenderer: MKOverlayRenderer {

public var fillColor = UIColor.red
public var strokeColor = UIColor.blue
public var lineWidth: CGFloat = 3
public var circle: MKCircle

public init(circle: MKCircle) {
    self.circle = circle
    super.init(overlay: circle)
}

public override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
    let path = UIBezierPath(rect: rect(for: MKMapRect.world))
    
    let excludePath = UIBezierPath(roundedRect: CGRect(x: circle.coordinate.latitude,
                                                       y: circle.coordinate.longitude,
                                                       width: circle.boundingMapRect.size.width,
                                                       height: circle.boundingMapRect.size.height),
                                   cornerRadius: CGFloat(circle.boundingMapRect.size.width))
    
    context.setFillColor(fillColor.cgColor)
    
    path.append(excludePath)
    context.addPath(path.cgPath)
    context.fillPath(using: .evenOdd)
    
    context.addPath(excludePath.cgPath)
    context.setLineWidth(lineWidth / zoomScale)
    context.setStrokeColor(strokeColor.cgColor)
    context.strokePath()
}

}

0

There are 0 best solutions below