Custom Mkannotation Not Moving When Coordinate Set

custom MKAnnotation not moving when coordinate set

If you're going to manually post those change events, you have to call willChangeValue(forKey:) in willSet, too. In Swift 4:

var coordinate: CLLocationCoordinate2D {
willSet {
willChangeValue(for: \.coordinate)
}
didSet {
didChangeValue(for: \.coordinate)
}
}

Or in Swift 3:

var coordinate: CLLocationCoordinate2D {
willSet {
willChangeValue(forKey: #keyPath(coordinate))
}
didSet {
didChangeValue(forKey: #keyPath(coordinate))
}
}

Or, much easier, just specify it as a dynamic property and this notification stuff is done for you.

@objc dynamic var coordinate: CLLocationCoordinate2D

For Swift 2 version, see previous rendition of this answer.

Swift -How to Update Data in Custom MKAnnotation Callout?

There are a few issues:

  1. You need to use the @objc dynamic qualifier for any properties you want to observe. The standard callout performs Key-Value Observation (KVO) on title and subtitle. (And the annotation view observes changes to coordinate.)

  2. If you want to observe userid and distance, you have to make those @objc dynamic as well. Note, you’ll have to make distance be non-optional to make that observable:

    var distance: CLLocationDistance

    So:

    class CustomAnnotation: NSObject, MKAnnotation {
    // standard MKAnnotation properties

    @objc dynamic var coordinate: CLLocationCoordinate2D
    @objc dynamic var title: String?
    @objc dynamic var subtitle: String?

    // additional custom properties

    @objc dynamic var userId: String
    @objc dynamic var distance: CLLocationDistance

    init(coordinate: CLLocationCoordinate2D, title: String, subtitle: String, userId: String, distance: CLLocationDistance) {
    self.userId = userId
    self.distance = distance
    self.coordinate = coordinate
    self.title = title
    self.subtitle = subtitle

    super.init()
    }
    }
  3. Like I said, the standard callout observes title and subtitle. While you have to make the annotation properties observable, if you’re going to build your own detailCalloutAccessoryView, you’re going to have to do your own KVO:

    class CustomAnnotationView: MKMarkerAnnotationView {
    private let customClusteringIdentifier = "..."

    override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
    super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
    canShowCallout = true
    detailCalloutAccessoryView = createCallOutWithDataFrom(customAnnotation: annotation as? CustomAnnotation)
    clusteringIdentifier = customClusteringIdentifier
    }

    required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
    }

    deinit {
    removeAnyObservers()
    }

    override var annotation: MKAnnotation? {
    didSet {
    removeAnyObservers()
    clusteringIdentifier = customClusteringIdentifier
    if let customAnnotation = annotation as? CustomAnnotation {
    updateAndAddObservers(for: customAnnotation)
    }
    }
    }

    private var subtitleObserver: NSKeyValueObservation?
    private var userObserver: NSKeyValueObservation?
    private var distanceObserver: NSKeyValueObservation?

    private let subtitleLabel: UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
    }()

    private let userLabel: UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
    }()

    private let distanceLabel: UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
    }()
    }

    private extension CustomAnnotationView {
    func updateAndAddObservers(for customAnnotation: CustomAnnotation) {
    subtitleLabel.text = customAnnotation.subtitle
    subtitleObserver = customAnnotation.observe(\.subtitle) { [weak self] customAnnotation, _ in
    self?.subtitleLabel.text = customAnnotation.subtitle
    }

    userLabel.text = customAnnotation.userId
    userObserver = customAnnotation.observe(\.userId) { [weak self] customAnnotation, _ in
    self?.userLabel.text = customAnnotation.userId
    }

    distanceLabel.text = "\(customAnnotation.distance) meters"
    distanceObserver = customAnnotation.observe(\.distance) { [weak self] customAnnotation, _ in
    self?.distanceLabel.text = "\(customAnnotation.distance) meters"
    }
    }

    func removeAnyObservers() {
    subtitleObserver = nil
    userObserver = nil
    distanceObserver = nil
    }

    func createCallOutWithDataFrom(customAnnotation: CustomAnnotation?) -> UIView {
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(subtitleLabel)
    view.addSubview(userLabel)
    view.addSubview(distanceLabel)

    NSLayoutConstraint.activate([
    subtitleLabel.topAnchor.constraint(equalTo: view.topAnchor),
    subtitleLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor),
    subtitleLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor),
    subtitleLabel.bottomAnchor.constraint(equalTo: userLabel.topAnchor),

    userLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor),
    userLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor),
    userLabel.bottomAnchor.constraint(equalTo: distanceLabel.topAnchor),

    distanceLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor),
    distanceLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor),
    distanceLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor)
    ])

    if let customAnnotation = customAnnotation {
    updateAndAddObservers(for: customAnnotation)
    }

    return view
    }
    }

That yields:
animated callout changes

Use MKAnnotation to move on the next View Controller

Create a segue from your mapViewController to your destination viewController and then do it like this:

func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
self.performSegue(withIdentifier: "destViewController", sender: nil)
}

Here is a sample project I created that shows you how it works.

To edit the segue identifier do this:
Sample Image

Custom MKAnnotation Pin executing specific action when clicked -- custom pin not showing up

Interesting, I tested your code, altering the coordinates to be in New York (simulator location) and the button works fine for me. Are you sure your custom coordinates are where you want them? And why not use the user's location?

Try this:

func determineCurrentLocation() {
mapView.delegate = self
locationManager = CLLocationManager()
locationManager.delegate = self
mapView.showsUserLocation = true
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.startUpdatingLocation()
}
}

@IBAction func tulipButton(_ sender: Any) {
dropPin()
}

func dropPin() { // Using the user's location
guard let location = locationManager.location else { return }
let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
tulipPin = customPin(Title: "username", Subtitle: "caption", coordinate: center)
self.mapView.addAnnotation(tulipPin)
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locationManager.location else { return }
let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05))
mapView.setRegion(region, animated: true)
}

func mapView(_ mapview: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !(annotation is MKUserLocation) else { return nil }
let annotationView = MKAnnotationView(annotation: tulipPin, reuseIdentifier: "tulip")
annotationView.image = UIImage(named: "tulip")
annotationView.canShowCallout = true
annotationView.calloutOffset = CGPoint(x: -5, y: 5)
// let transform = CGAffineTransform(scaleX: 0.07, y: 0.07)
// annotationView.transform = transform
return annotationView
}

Sample Image



Related Topics



Leave a reply



Submit