I am having some trouble getting a custom annotation to load inside of my map view when I try to place a pin.
import UIKit
import MapKit
import CoreLocation
class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate{
@IBAction func ReportBtn(sender: AnyObject) {
//MARK: Report Date And Time Details
let ReportTime = NSDate()
let TimeStamp = NSDateFormatter()
TimeStamp.timeStyle = NSDateFormatterStyle.ShortStyle
TimeStamp.dateStyle = NSDateFormatterStyle.ShortStyle
TimeStamp.stringFromDate(ReportTime)
//MARK: Default Point Annotation Begins
let ReportAnnotation = MKPointAnnotation()
ReportAnnotation.title = "Annotation Created"
ReportAnnotation.subtitle = ReportTime.description
ReportAnnotation.coordinate = locationManager.location!.coordinate
mapView(MainMap, viewForAnnotation: ReportAnnotation)
MainMap.addAnnotation(ReportAnnotation)
}
@IBOutlet weak var MainMap: MKMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.startUpdatingLocation()
self.MainMap.showsUserLocation = true
}
//MARK: - Location Delegate Methods
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02 ))
self.MainMap.setRegion(region, animated: true)
//self.locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError){
print(error.localizedDescription)
}
//MARK:Custom Annotation Begins Here
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
guard !annotation.isKindOfClass(MKUserLocation) else {
return nil
}
/*if annotation.isKindOfClass(MKUserLocation){
//emty return, guard wasn't cooperating
}else{
return nil
}*/
let annotationIdentifier = "AnnotationIdentifier"
var annotationView: MKAnnotationView?
if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(annotationIdentifier){
annotationView = dequeuedAnnotationView
annotationView?.annotation = annotation
}
else{
let av = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
av.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure)
annotationView = av
}
if let annotationView = annotationView {
annotationView.canShowCallout = true
annotationView.image = UIImage(named: "image.png")
}
return annotationView
}
}
I am positive that the button functionality works perfect. With the current code, dumped above, the default red pin annotation appears right where it should. When I tap on the pin, the description I specified also appears without an issue. The only problem I am having with this code is that I cannot get my image to take the place of the boring, default red pin
I recommend subclassing `MKPointAnnotation.
I have included only the necessary code to display a custom map pin. Think of it as a template.
Outline
We will create a point annotation object and assigning a custom image name with the CustomPointAnnotation
class.
We will subclass the MKPointAnnotation
to set image and assign it on the delegate protocol method viewForAnnotation
.
We will add an annotation view to the map after setting the coordinate of the point annotation with a title and a subtitle.
We will implement the viewForAnnotation
method which is an MKMapViewDelegate
protocol method which gets called for pins to display on the map. viewForAnnotation
protocol method is the best place to customise the pin view and assign a custom image to it.
We will dequeue and return a reusable annotation for the given identifier and cast the annotation to our custom CustomPointAnnotation
class in order to access the image name of the pin.
We will create a new image set in Assets.xcassets
and place [email protected] and [email protected] accordingly.
Don't forget plist.
NSLocationAlwaysUsageDescription
and NSLocationWhenInUseUsageDescription
As always test on a real device.
The swizzle 🌀
//1
CustomPointAnnotation.swift
import UIKit
import MapKit
class CustomPointAnnotation: MKPointAnnotation {
var pinCustomImageName:String!
}
//2
ViewController.swift
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
@IBOutlet weak var pokemonMap: MKMapView!
let locationManager = CLLocationManager()
var pointAnnotation:CustomPointAnnotation!
var pinAnnotationView:MKPinAnnotationView!
override func viewDidLoad() {
super.viewDidLoad()
//Mark: - Authorization
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
pokemonMap.delegate = self
pokemonMap.mapType = MKMapType.Standard
pokemonMap.showsUserLocation = true
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = CLLocationCoordinate2D(latitude: 35.689949, longitude: 139.697576)
let center = location
let region = MKCoordinateRegionMake(center, MKCoordinateSpan(latitudeDelta: 0.025, longitudeDelta: 0.025))
pokemonMap.setRegion(region, animated: true)
pointAnnotation = CustomPointAnnotation()
pointAnnotation.pinCustomImageName = "Pokemon Pin"
pointAnnotation.coordinate = location
pointAnnotation.title = "POKéSTOP"
pointAnnotation.subtitle = "Pick up some Poké Balls"
pinAnnotationView = MKPinAnnotationView(annotation: pointAnnotation, reuseIdentifier: "pin")
pokemonMap.addAnnotation(pinAnnotationView.annotation!)
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print(error.localizedDescription)
}
//MARK: - Custom Annotation
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let reuseIdentifier = "pin"
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseIdentifier)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseIdentifier)
annotationView?.canShowCallout = true
} else {
annotationView?.annotation = annotation
}
let customPointAnnotation = annotation as! CustomPointAnnotation
annotationView?.image = UIImage(named: customPointAnnotation.pinCustomImageName)
return annotationView
}
}