How to generate different pins on mapview in Swift 3? - ios

I am coming to a problem where I try to generate different icons to show on the map view of places. But, I need some help from you guys. So far, I have hard-coded a pin to show on the map view. I also, have different pins in my assets, I want to show them by generating it on the mapview. How can I generate different icons to show on my map view from the API? Thanks for the help.
Here is my code:
import UIKit
import MapKit
import CoreLocation
class MapViewController: BaseViewController{
#IBOutlet weak var leadingConstraints: NSLayoutConstraint!
#IBOutlet weak var menuView: UIView!
#IBOutlet weak var mapView: MKMapView!
fileprivate let locationManager = CLLocationManager()
fileprivate var startedLoadingPOIs = false
fileprivate var places = [Place]()
fileprivate var arViewController: ARViewController!
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
var nearMeIndexSelected = NearMeIndexTitle()
var menuShowing = false
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
locationManager.requestWhenInUseAuthorization()
//making shadow of our menu view
menuView.layer.shadowOpacity = 1
menuView.layer.shadowRadius = 7
}
#IBAction func showARController(_ sender: Any) {
arViewController = ARViewController()
arViewController.dataSource = self
arViewController.maxVisibleAnnotations = 30
arViewController.headingSmoothingFactor = 0.05
arViewController.setAnnotations(places)
self.navigationController!.pushViewController(arViewController, animated: true)
}
}
extension MapViewController: CLLocationManagerDelegate, MKMapViewDelegate {
// // Changing the Pin Color on the map.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
mapView.tintColor = #colorLiteral(red: 0.8823529412, green: 0.1647058824, blue: 0.1333333333, alpha: 1)
return nil
} else {
let annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "pin")
let pin = mapView.view(for: annotation) ?? MKAnnotationView(annotation: annotation, reuseIdentifier: nil)
pin.image = UIImage(named: "pins")
return pin
return annotationView
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if locations.count > 0 {
let location = locations.last!
print("Accuracy: \(location.horizontalAccuracy)")
if location.horizontalAccuracy < 100 {
manager.stopUpdatingLocation()
let span = MKCoordinateSpan(latitudeDelta: 0.013, longitudeDelta: 0.013)
let region = MKCoordinateRegion(center: location.coordinate, span: span)
mapView.region = region
if !startedLoadingPOIs {
DispatchQueue.main.async {
self.activityIndicator.startAnimating()
}
startedLoadingPOIs = true
let loader = PlacesLoader()
loader.loadPOIS(location: location, radius: 1500) { placesDict, error in
if let dict = placesDict {
guard let placesArray = dict.object(forKey: "results") as? [NSDictionary] else { return }
for placeDict in placesArray {
let latitude = placeDict.value(forKeyPath: "geometry.location.lat") as! CLLocationDegrees
let longitude = placeDict.value(forKeyPath: "geometry.location.lng") as! CLLocationDegrees
let reference = placeDict.object(forKey: "reference") as! String
let name = placeDict.object(forKey: "name") as! String
let address = placeDict.object(forKey: "vicinity") as! String
let location = CLLocation(latitude: latitude, longitude: longitude)
let place = Place(location: location, reference: reference, name: name, address: address)
self.places.append(place)
let annotation = PlaceAnnotation(location: place.location!.coordinate, title: place.placeName)
DispatchQueue.main.async {
self.mapView.addAnnotation(annotation)
}
}
DispatchQueue.main.async {
self.activityIndicator.stopAnimating()
self.mapView.isHidden = false
}
}
}
}
}
}
}
}

You can compare the coordinate of the annotation and specify custom pin for that Annotation.
if annotation.coordinate == "Your Custom Pin Coordinate" { //set custom pin }
Suppose I want to add a custom pin for my selected Place.
var selectedPlace: PlaceAnnotation
Inside your loop. suppose my selected place is "toronto"
if name == "toronto" { self.selectedPlace = annotation }
Then in ViewForAnnotation method
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation.coordinate = selectedPlace.coordinate {
pin.image = UIImage(named: "YOUR SELECTED IMAGE")
}
}

See here my demo to create a custom pin view customPinAnnotationButton
Here is the method to draw annotation with image , I subclassed MKAnoationView
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
{
if annotation is MyAnnotation == false
{
return nil
}
let senderAnnotation = annotation as! MyAnnotation
let pinReusableIdentifier = senderAnnotation.pinColor.rawValue
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: pinReusableIdentifier)
if annotationView == nil
{
annotationView = MKAnnotationView(annotation: senderAnnotation, reuseIdentifier: pinReusableIdentifier)
annotationView!.canShowCallout = false
}
if senderAnnotation.pinColor == PinColor.Green
{
let pinImage = UIImage(named:"directMarker3.png")
annotationView!.image = pinImage
}
return annotationView
}
here to add an annotation
let blueLocation = CLLocationCoordinate2D(latitude:30.45454554, longitude: 29.646727)
let blueAnnotation = MyAnnotation(coordinate: blueLocation, title:"ghghhg",subtitle: "hgnhhghghg",pinColor: .Green ,uid:"hghg",type:"provider")
self.mymap.addAnnotation(blueAnnotation)
self.mymap.showAnnotations(self.mymap.annotations, animated: true)

1.Define subclass of MKPointAnnotation:
class MyPointAnnotation: MKPointAnnotation {
var imageName: String = ""
}
2.Set image name.
let annotation = MyPointAnnotation()
annotation.coordinate = coordinate
annotation.title = "title"
annotation.subtitle = "subtitle"
annotation.imageName = "pin" // Set image name here
self.mapView.addAnnotation(annotation)
3.Load image in viewFor delegate method
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let reuseId = "image"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
if pinView == nil {
pinView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView?.canShowCallout = true
let annotation = annotation as! MyPointAnnotation
pinView?.image = UIImage(named: annotation.imageName)
let rightButton: AnyObject! = UIButton(type: UIButtonType.detailDisclosure)
pinView?.rightCalloutAccessoryView = rightButton as? UIView
}
else {
pinView?.annotation = annotation
}
return pinView
}

Related

how to give name to pin annotation in the MapKit?

I want to give name to the green and right pin annotation above.
I see a video tutorial, and he can give name to the annotation by using annotation.title = but I don't know why I can get the name correctly show in my MapKit.
here is the code I use
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapKit: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapKit.delegate = self
let bakrieTowerCoordinate = CLLocation(latitude: -6.23860724759536, longitude: 106.789429759178)
let GBKCoordinate = CLLocation(latitude: -6.23864960081552, longitude: 106.789627819772)
let locationGBK : CLLocationCoordinate2D = CLLocationCoordinate2DMake(-6.23864960081552, 106.789627819772)
let locationBakrieToweer : CLLocationCoordinate2D = CLLocationCoordinate2DMake(-6.23860724759536, 106.789429759178)
let annotation = MKPointAnnotation()
annotation.coordinate = locationGBK
annotation.title = "GBK"
annotation.subtitle = "Stadion"
mapKit.addAnnotation(annotation)
let annotation2 = MKPointAnnotation()
annotation2.coordinate = locationBakrieToweer
annotation2.title = "Bakrie Tower"
annotation2.subtitle = "Office"
mapKit.addAnnotation(annotation2)
zoomMapOn(location1: GBKCoordinate, location2: bakrieTowerCoordinate)
}
func zoomMapOn(location1: CLLocation, location2: CLLocation) {
let distanceOf2CoordinateInMeters = location1.distance(from: location2)
let radius = distanceOf2CoordinateInMeters * 3
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location1.coordinate, radius, radius)
mapKit.setRegion(coordinateRegion, animated: true)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "pin")
guard let locationName = annotation.title else {return nil}
if locationName == "GBK" {
annotationView.pinTintColor = UIColor.green
} else if locationName == "Bakrie Tower" {
annotationView.pinTintColor = UIColor.red
}
return annotationView
}
}
Add this code to your view controller -
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapKit: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapKit.delegate = self
let bakrieTowerCoordinate = CLLocation(latitude: -6.23860724759536, longitude: 106.789429759178)
let GBKCoordinate = CLLocation(latitude: -6.23864960081552, longitude: 106.789627819772)
let locationGBK : CLLocationCoordinate2D = CLLocationCoordinate2DMake(-6.23864960081552, 106.789627819772)
let locationBakrieToweer : CLLocationCoordinate2D = CLLocationCoordinate2DMake(-6.23860724759536, 106.789429759178)
let annotation = MKPointAnnotation()
annotation.coordinate = locationGBK
annotation.title = "GBK"
annotation.subtitle = "Stadion"
mapKit.addAnnotation(annotation)
let annotation2 = MKPointAnnotation()
annotation2.coordinate = locationBakrieToweer
annotation2.title = "Bakrie Tower"
annotation2.subtitle = "Office"
mapKit.addAnnotation(annotation2)
zoomMapOn(location1: GBKCoordinate, location2: bakrieTowerCoordinate)
}
func zoomMapOn(location1: CLLocation, location2: CLLocation) {
let distanceOf2CoordinateInMeters = location1.distance(from: location2)
let radius = distanceOf2CoordinateInMeters * 3
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location1.coordinate, radius, radius)
mapKit.setRegion(coordinateRegion, animated: true)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "pin")
guard let locationName = annotation.title else {return nil}
if locationName == "GBK" {
annotationView.canShowCallout = true
} else if locationName == "Bakrie Tower" {
annotationView.pinTintColor = UIColor.red
}
annotationView.canShowCallout = true // Add this line in your code
return annotationView
}
}
When you tap on the pin, it will show the text, Like -
Just Add
annotationView.canShowCallout = true inside your mapView(_ mapView:). Thank you.
You need to set this property in mapView(_:viewFor:) before returning your annotationView:
annotationView.canShowCallout = true
Now when you tap the pin, it will show your text.

Open maps app with custom callout view and multiple annotations

I have made an project and followed a tutorial on the internet. It shows annotations and has a custom callout view.I have added a label with a button feature which is shown in my screenshot. I now would like some help to get the feature to start maps app from my project. I have made comments in the project which shows what i have done and what i need help with
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate, UISearchBarDelegate {
#IBOutlet var mapView: MKMapView!
#IBOutlet var searchBarMap: UISearchBar!
var coordinates: [[Double]]!
var names:[String]!
var addresses:[String]!
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation
{
return nil
}
if annotation is MKPointAnnotation
{
return nil
}
var annotationView = self.mapView.dequeueReusableAnnotationView(withIdentifier: "Pin")
if annotationView == nil{
annotationView = AnnotationView(annotation: annotation, reuseIdentifier: "Pin")
annotationView?.canShowCallout = false
}else{
annotationView?.annotation = annotation
}
annotationView?.image = UIImage(named: "parking-sign")
return annotationView
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
searchBarMap.delegate = self
coordinates = [[57.638486,18.299698],[57.636859,18.300468],[57.634807, 18.293389]]// Latitude,Longitude
names = ["Österport","Åhléns","Söderport/busstation"]
addresses = ["regler: p-skiva 2 timmar 9-18, oftast få platser lediga","stor med två våningar, övre plan oftast väl fylld och komplicerade parkeringsrutor","Nära om du vill till adelsgatan"]
self.mapView.delegate = self
for i in 0...2
{
let coordinate = coordinates[i]
let point = StarbucksAnnotation(coordinate: CLLocationCoordinate2D(latitude: coordinate[0] , longitude: coordinate[1] ))
point.name = names[i]
point.address = addresses[i]
self.mapView.addAnnotation(point)
}
let region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 57.630615, longitude: 18.303023), span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1))
self.mapView.setRegion(region, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func mapView(_ mapView: MKMapView,
didSelect view: MKAnnotationView)
{
// 1
if view.annotation is MKUserLocation
{
return
}
if view.annotation is MKPointAnnotation
{
return
}
let starbucksAnnotation = view.annotation as! StarbucksAnnotation
let views = Bundle.main.loadNibNamed("CustomCalloutView", owner: nil, options: nil)
let calloutView = views?[0] as! CustomCalloutView
calloutView.starbucksName.text = starbucksAnnotation.name
calloutView.starbucksAddress.text = starbucksAnnotation.address
// declaring label as a button
let button = UIButton(frame: calloutView.directions.frame)
button.addTarget(self, action: #selector(ViewController.openInMaps(sender:)), for: .touchUpInside)
calloutView.addSubview(button)
calloutView.center = CGPoint(x: view.bounds.size.width / 2, y: -calloutView.bounds.size.height*0.52)
view.addSubview(calloutView)
mapView.setCenter((view.annotation?.coordinate)!, animated: true)
}
func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
if view.isKind(of: AnnotationView.self)
{
for subview in view.subviews
{
subview.removeFromSuperview()
}
}
}
//I want to know what i should fill this function with to open maps and give me directions
func openInMaps(sender: UIButton)
{
//This is what i tested so far
let coordinates1 = coordinates
let point = StarbucksAnnotation(coordinate: CLLocationCoordinate2D(latitude: coordinates1[0] , longitude: coordinates1[1] ))
let regionDistance:CLLocationDistance = 10000
let regionSpan = MKCoordinateRegionMakeWithDistance(point, regionDistance, regionDistance)
let options = [
MKLaunchOptionsMapCenterKey: NSValue(mkCoordinate: regionSpan.center),
MKLaunchOptionsMapSpanKey: NSValue(mkCoordinateSpan: regionSpan.span)
]
let placemark = MKPlacemark(coordinate: point, addressDictionary: nil)
let mapItem = MKMapItem(placemark: placemark)
mapItem.name = "destination"
mapItem.openInMaps(launchOptions: options)
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBarMap.resignFirstResponder()
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(searchBar.text!) { (placemarks:[CLPlacemark]?, error:Error?) in
if error == nil {
let placemark = placemarks?.first
let anno = MKPointAnnotation()
anno.coordinate = (placemark?.location?.coordinate)!
anno.title = self.searchBarMap.text!
self.mapView.addAnnotation(anno)
self.mapView.selectAnnotation(anno, animated: true)
}else{
print(error?.localizedDescription ?? "error")
}
}
}
}

show custom annotation in mapkit

I'm trying to show an image annotation instead of a pin annotation on the mapkit. I'm using this code:
import UIKit
import MapKit
class ViewController2: UIViewController , MKMapViewDelegate {
#IBOutlet var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
let coordinate = CLLocationCoordinate2DMake(26.889281, 75.836042)
let region = MKCoordinateRegion(center: coordinate, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
mapView.setRegion(region, animated: true)
var info1 = CustomPointAnnotation()
info1.coordinate = CLLocationCoordinate2DMake(26.889281, 75.836042)
info1.title = "Info1"
info1.subtitle = "Subtitle"
info1.imageName = "taxi"
var info2 = CustomPointAnnotation()
info2.coordinate = CLLocationCoordinate2DMake(26.862280, 75.815098)
info2.title = "Info2"
info2.subtitle = "Subtitle"
info2.imageName = "smile"
mapView.addAnnotation(info1)
mapView.addAnnotation(info2)
mapView.showAnnotations(mapView.annotations, animated: true)
}
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
print("delegate called")
if !(annotation is CustomPointAnnotation) {
return nil
}
let reuseId = "test"
var anView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
if anView == nil {
anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
anView?.canShowCallout = true
}
else {
anView?.annotation = annotation
}
//Set annotation-specific properties **AFTER**
//the view is dequeued or created...
let cpa = annotation as! CustomPointAnnotation
anView?.image = UIImage(named:cpa.imageName)
return anView
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(_ animated: Bool) {
}
}
class CustomPointAnnotation: MKPointAnnotation {
var imageName: String!
}
I think this method is not calling viewForAnnotation, although I connect the delegate with viewcontroller : mapView.delegate = self.
I still see the pin annotation instead of custominnotation on the map:
now when implement this code :
import UIKit
import MapKit
class ViewController2: UIViewController , MKMapViewDelegate {
#IBOutlet var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
let coordinate = CLLocationCoordinate2DMake(26.889281, 75.836042)
let region = MKCoordinateRegion(center: coordinate, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
mapView.setRegion(region, animated: true)
let annotation = MKPointAnnotation()
annotation.title = "Annotation Created"
annotation.subtitle = "mahdi"
annotation.coordinate = CLLocationCoordinate2DMake(26.889281, 75.836042)
let annotation2 = MKPointAnnotation()
annotation2.title = "Annotation Created"
annotation2.subtitle = "mahdi"
annotation2.coordinate = CLLocationCoordinate2DMake(26.862280, 75.815098)
mapView.addAnnotation(annotation)
mapView.addAnnotation(annotation2)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !annotation.isKind(of: MKUserLocation.self) else {
return nil
}
let annotationIdentifier = "AnnotationIdentifier"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: annotationIdentifier)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
annotationView!.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
annotationView!.canShowCallout = true
}
else {
annotationView!.annotation = annotation
}
annotationView!.image = UIImage(named: "taxi")
return annotationView
}
i can see the two images annotations like this :
enter image description here
now i want to include this image with user location , i try with this code but still see the red pin annotation instead of image
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = manager.location?.coordinate {
userLocation = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
// print(userLocation)
if driverOnTheWay == false {
let region = MKCoordinateRegion(center: userLocation, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
self.mapView.setRegion(region, animated: true)
self.mapView.removeAnnotations(self.mapView.annotations)
let annotation = MKPointAnnotation()
annotation.title = "مكانك هنا"
annotation.subtitle = "mahdi"
annotation.coordinate = userLocation
self.mapView.addAnnotation(annotation)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !annotation.isKind(of: MKUserLocation.self) else {
return nil
}
let annotationIdentifier = "AnnotationIdentifier"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: annotationIdentifier)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
annotationView!.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
annotationView!.canShowCallout = true
}
else {
annotationView!.annotation = annotation
}
annotationView!.image = UIImage(named: "car")
return annotationView
}
how can show car image with user location

How to add custom images to annotations in Mapview Swift ios?

var lat:CLLocationDegrees = 40.748708
var long:CLLocationDegrees = -73.985643
var latDelta:CLLocationDegrees = 0.01
var longDelta:CLLocationDegrees = 0.01
var span:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, longDelta)
var location:CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat, long)
var region:MKCoordinateRegion = MKCoordinateRegionMake(location, span)
mapView.setRegion(region, animated: true)
var information = MKPointAnnotation()
information.coordinate = location
information.title = "Test Title!"
information.subtitle = "Subtitle"
mapView.addAnnotation(information)
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if !(annotation is MKPointAnnotation) {
return nil
}
let reuseId = "test"
var anView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
if anView == nil {
anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
anView?.image = UIImage(named:"annotation")
anView?.canShowCallout = true
}
else {
anView?.annotation = annotation
}
return anView
}
I need to load custom image for the annotation in Mapview. I have an image named "Annotation" and I am trying to call it in viewfor annotation method. How can I achieve this?
Here is the answer:
Swift 4:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
// Don't want to show a custom image if the annotation is the user's location.
guard !(annotation is MKUserLocation) else {
return nil
}
// Better to make this class property
let annotationIdentifier = "AnnotationIdentifier"
var annotationView: MKAnnotationView?
if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: 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 {
// Configure your annotation view here
annotationView.canShowCallout = true
annotationView.image = UIImage(named: "yourImage")
}
return annotationView
}
Swift 3:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
// Don't want to show a custom image if the annotation is the user's location.
guard !(annotation is MKUserLocation) else {
return nil
}
// Better to make this class property
let annotationIdentifier = "AnnotationIdentifier"
var annotationView: MKAnnotationView?
if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: annotationIdentifier) {
annotationView = dequeuedAnnotationView
annotationView?.annotation = annotation
}
else {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
annotationView?.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
}
if let annotationView = annotationView {
// Configure your annotation view here
annotationView.canShowCallout = true
annotationView.image = UIImage(named: "yourImage")
}
return annotationView
}
Swift 2.2:
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
// Don't want to show a custom image if the annotation is the user's location.
guard !annotation.isKindOfClass(MKUserLocation) 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 {
// Configure your annotation view here
annotationView.canShowCallout = true
annotationView.image = UIImage(named: "yourImage")
}
return annotationView
}
Swift 4.0
var coordinates: [[Double]]!
var addresses:[String]!
In viewDidload() add following code to add annotations to MapvView.
coordinates = [[28.4344,72.5401],[28.85196,72.3944],[28.15376,72.1953]]// Latitude,Longitude
addresses = ["Address1","Address2","Address3"]
self.mapView.delegate = self // set MapView delegate to self
for i in 0...2 {
let coordinate = coordinates[i]
let point = CustomAnnotation(coordinate: CLLocationCoordinate2D(latitude: coordinate[0] , longitude: coordinate[1] )) // CustomAnnotation is class and pass the required param
point.address = addresses[i] // passing only address to pin, you can add multiple properties according to need
self.mapView.addAnnotation(point)
}
let region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 28.856614, longitude: 72.3522219), span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1))
self.mapView.setRegion(region, animated: true)
Add new class having name CustomAnnotation inherited from MKAnnotation for our custom annotation
import MapKit
class CustomAnnotation: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var address: String!
init(coordinate: CLLocationCoordinate2D) {
self.coordinate = coordinate
}
}
Add one more class having name AnnotationView inherited from MKAnnotationView. I am showing custom callout so it it is required to to override the overridefuncpoint() method to receive touch in custom callout view.
import MapKit
class AnnotationView: MKAnnotationView
{
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let hitView = super.hitTest(point, with: event)
if (hitView != nil)
{
self.superview?.bringSubview(toFront: self)
}
return hitView
}
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
let rect = self.bounds;
var isInside: Bool = rect.contains(point);
if(!isInside)
{
for view in self.subviews
{
isInside = view.frame.contains(point);
if isInside
{
break;
}
}
}
return isInside;
}
}
Now implement viewForannotation MapView delegate as follow
extension YourViewC: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation
{
return nil
}
var annotationView = self.mapView.dequeueReusableAnnotationView(withIdentifier: "CustomPin")
if annotationView == nil{
annotationView = AnnotationView(annotation: annotation, reuseIdentifier: "CustomPin")
annotationView?.canShowCallout = false
}else{
annotationView?.annotation = annotation
}
annotationView?.image = UIImage(named: "bluecircle") // Pass name of your custom image
return annotationView
}
func mapView(_ mapView: MKMapView,
didSelect view: MKAnnotationView){
let annotation = view.annotation as? CustomAnnotation
print(annotation?.address) // get info you passed on pin
// write code here to add custom view on tapped annotion
}
The best way to achieve this is using custom class to store annotations.
import UIKit
import MapKit
import CoreLocation
class Annotation: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D = CLLocationCoordinate2D()
var title: String?
var subtitle: String?
var strTitle = ""
var strImgUrl = ""
var strDescr = ""
init(coordinates location: CLLocationCoordinate2D, title1: String, description: String, imgURL: String) {
super.init()
coordinate = location
title = title1
subtitle = description
strTitle = title1
strImgUrl = imgURL
strDescr = description
}
}
Now use this class to store annotation and populate your pins.
// MapViewController.swift
let myAnnotation1: Annotation = Annotation.init(coordinates: CLLocationCoordinate2D.init(latitude: 30.733051, longitude: 76.763042), title1: "The Mayflower Renaissance Hotel", description: "The Histroic hotel has been the site of saveral dramatic locations.", imgURL: "custom.jpg")
self.uvMApView.addAnnotation(myAnnotation1)
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if (annotation is MKUserLocation) {
return nil
}
// try to dequeue an existing pin view first
let AnnotationIdentifier = "AnnotationIdentifier"
let myAnnotation1 = (annotation as! Annotation)
let pinView = MKAnnotationView(annotation: annotation, reuseIdentifier: AnnotationIdentifier)
pinView.canShowCallout = true
pinView.image = UIImage(named: myAnnotation1. strImgUrl)!
return pinView
}
After spending lot of time, i came up with a simple code.
1. Don't use .pdf images, use only .png images with three different sizes such as 1x, 2x, 3x. Below is my sample code.
#IBOutlet var mapView: MKMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
mapViewSetup()
}
func mapViewSetup(){
self.locationManager.requestAlwaysAuthorization()
// For use in foreground
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
mapView.delegate = self
mapView.mapType = .standard
mapView.isZoomEnabled = true
mapView.isScrollEnabled = true
mapView.showsUserLocation = false
if let coor = mapView.userLocation.location?.coordinate{
mapView.setCenter(coor, animated: true)
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue:CLLocationCoordinate2D = manager.location!.coordinate
mapView.mapType = MKMapType.standard
let span = MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
let region = MKCoordinateRegion(center: locValue, span: span)
mapView.setRegion(region, animated: true)
let annotation = MKPointAnnotation()
annotation.coordinate = locValue
annotation.title = "Arshad"
annotation.subtitle = "BrightSword Technologies Pvt Ltd"
mapView.addAnnotation(annotation)
self.locationManager.stopUpdatingLocation()
//centerMap(locValue)
}
private func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print(error.localizedDescription)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "customannotation")
annotationView.image = UIImage(named: "icon_location_pin")
annotationView.canShowCallout = true
return annotationView
}
Hope it will help someone.
You can also do like this:
let reuseId = "pin"
var your_pin = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
let your_image = UIImage (named: "your_image")
pinView?.image = your_image
pinView?.canShowCallout = true
I think it is the more easily answer.

How to change MKAnnotation Color using Swift?

I have MKAnnotations set up on a map, but I would like to change the color of the annotations for different scenario's. Is there a way to change the color of the annotation?
Here is my code below, how would I implement the color change?
override func viewDidAppear(animated: Bool) {
var annotationQuery = PFQuery(className: "Post")
currentLoc = PFGeoPoint(location: MapViewLocationManager.location)
//annotationQuery.whereKey("Location", nearGeoPoint: currentLoc, withinMiles: 10)
annotationQuery.whereKeyExists("Location")
annotationQuery.findObjectsInBackgroundWithBlock {
(points, error) -> Void in
if error == nil {
// The find succeeded.
println("Successful query for annotations")
// Do something with the found objects
let myPosts = points as! [PFObject]
for post in myPosts {
let point = post["Location"] as! PFGeoPoint
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2DMake(point.latitude, point.longitude)
annotation.title = post["title"] as! String!
annotation.subtitle = post["username"] as! String!
self.mapView.addAnnotation(annotation)
}
} else {
// Log details of the failure
println("Error: \(error)")
}
}
You can use custom images for annotation view or use predefined MKPinAnnotationView with pinColor. But pinColors limited to Red, Green and Purple.
Some example:
import UIKit
import MapKit
class Annotation: NSObject, MKAnnotation
{
var coordinate: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
var custom_image: Bool = true
var color: MKPinAnnotationColor = MKPinAnnotationColor.Purple
}
class ViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
self.mapView.delegate = self;
let annotation = Annotation.new()
mapView.addAnnotation(annotation)
let annotation2 = Annotation.new()
annotation2.coordinate = CLLocationCoordinate2D(latitude: 0.0, longitude: 1.0)
annotation2.custom_image = false
mapView.addAnnotation(annotation2)
let annotation3 = Annotation.new()
annotation3.coordinate = CLLocationCoordinate2D(latitude: 1.0, longitude: 0.0)
annotation3.custom_image = false
annotation3.color = MKPinAnnotationColor.Green
mapView.addAnnotation(annotation3)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if (annotation is MKUserLocation) {
return nil
}
var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
if anView == nil {
if let anAnnotation = annotation as? Annotation {
if anAnnotation.custom_image {
let reuseId = "custom_image"
anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
anView.image = UIImage(named:"custom_image")
}
else {
let reuseId = "pin"
let pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView.pinColor = anAnnotation.color
anView = pinView
}
}
anView.canShowCallout = false
}
else {
anView.annotation = annotation
}
return anView
}
}
Update:
Set delegate for mapView in viewDidLoad
You have to set it in the viewForAnnotation method.
In this tutorial is quite well explained how doing it.

Resources