I'm trying to give a user the ability to enter an address and have the map zoom to it which works.
I'd like to allow the user to drag the pin to another location then take the information of the location and use it for whatever.
I've tried and I've tried but the most I can get to work is changing the actual pin to a custom image. I've gone through several posts and tutorials (all for Objective-c) and even after converting code I still can't get this to work.
My custom annotation view:
import Foundation
import MapKit
class CustomAnnotationView: MKAnnotationView {
var coordinate:CLLocationCoordinate2D!
init(coordinate:CLLocationCoordinate2D) {
super.init()
self.coordinate = coordinate
}
override init(frame: CGRect) {
super.init(frame: CGRect())
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(annotation: MKAnnotation!, reuseIdentifier: String!) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
image = UIImage(named: "pin")
draggable = true
canShowCallout = true
}
func setCoordinate(newCoordinate: CLLocationCoordinate2D){
self.coordinate = newCoordinate;
}
}
My controller that houses my mapView:
import Foundation
import MapKit
class LocationViewController : UIViewController, MKMapViewDelegate {
@IBOutlet weak var mapView: MKMapView!
@IBOutlet weak var searchField: UITextField!
@IBOutlet weak var addressLabel: UILabel!
@IBOutlet weak var locationInstructions: UITextView!
@IBAction func didTapGoButton(sender: UIButton) {
var geocoder = CLGeocoder()
geocoder.geocodeAddressString(searchField.text, {(placemarks: [AnyObject]!, error: NSError!) -> Void in
if let placemark = placemarks?[0] as? CLPlacemark {
var region = self.mapView.region as MKCoordinateRegion
region.center = placemark.location.coordinate
region.span.longitudeDelta /= 30.0;
region.span.latitudeDelta /= 30.0;
self.mapView.zoomEnabled = true
self.mapView.scrollEnabled = true
self.mapView.addAnnotation(MKPlacemark(placemark: placemark))
self.mapView.setRegion(region, animated: true)
}
})
}
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if annotation.isKindOfClass(MKUserLocation) {
return nil
}
var pin = mapView.dequeueReusableAnnotationViewWithIdentifier("CustomAnnotationView")
if pin == nil {
NSLog("PIN NIL")
pin = CustomAnnotationView(annotation: annotation, reuseIdentifier: "CustomAnnotationView")
}
else
{
NSLog("PIN NOT NIL")
pin.annotation = annotation;
}
return pin;
}
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, didChangeDragState newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
if newState == MKAnnotationViewDragState.Starting
{
view.dragState = MKAnnotationViewDragState.Dragging
}
else if newState == MKAnnotationViewDragState.Ending || newState == MKAnnotationViewDragState.Canceling
{
view.dragState = MKAnnotationViewDragState.None;
}
}
What am I missing?
I can't find any Swift examples where this was done successfully.
The settable coordinate
property belongs in the object that implements the MKAnnotation
protocol.
The object that implements the MKAnnotation
protocol is the one you pass to addAnnotation
.
The MKAnnotationView
class (and your CustomAnnotationView
subclass) are NOT the objects that implement MKAnnotation
. They are the visual representation of the annotation model objects.
Here's what the Location and Maps Programming Guide says:
To implement minimal support for dragging:
- In your annotation objects, implement the setCoordinate: method to allow the map view to update the annotation’s coordinate point.
- When creating your annotation view, set its draggable property to YES.
Your "annotation objects" are different things from your "annotation views".
In didTapGoButton
, the code is adding an annotation of type MKPlacemark
which does not implement setCoordinate:
.
Instead, you'll need to use the built-in MKPointAnnotation
class which does implement setCoordinate:
or create your own custom class that implements the MKAnnotation
protocol (not a subclass of MKAnnotationView
) and provides a settable coordinate
property.
So instead of this:
self.mapView.addAnnotation(MKPlacemark(placemark: placemark))
do this:
let pa = MKPointAnnotation()
pa.coordinate = placemark.location.coordinate
pa.title = placemark.name //or whatever title you like
self.mapView.addAnnotation(pa)
You can still keep your CustomAnnotationView
class if you like but it's not necessary just to create an annotation view with a custom image and it definitely does not need a coordinate property.