Individual custom annotation callout swift - swift

I am creating a map which contains both custom annotation pins as well as images in the annotation callouts. The only problem is that I cannot figure out a way to have different images for different annotations. More specifically, I'm after having individual images for the annotation callouts. While I have found results on how to change the pin, I am struggling with finding any info for the callout and would appreciate any help. Below is the function for the annotations I am working with. Thank you.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !annotation.isKind(of: MKUserLocation.self) else {
return nil}
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: "pinAnnotation.png")
}
let imageName = "until.png"
let image = UIImage(named: imageName)
let imageView = UIImageView(image: image!)
annotationView?.detailCalloutAccessoryView = imageView
return annotationView
}
class ViewController2: UIViewController {
#IBOutlet var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
//Location for first Pin
let locationOne = CLLocationCoordinate2DMake(-47.016945, 167.852095)
//Location for map centering
let locationNZ = CLLocationCoordinate2DMake(-43.937462, 170.507813)
let span = MKCoordinateSpanMake(9, 9)
let region = MKCoordinateRegion(center: locationNZ, span: span)
mapView.setRegion(region, animated: true)
//Create annotation one
let annotation = MKPointAnnotation()
annotation.coordinate = locationOne
annotation.subtitle = "Park"
annotation.title = "Rakiura National Park"
//Add annotation to the map
mapView.addAnnotation(annotation)
mapView.delegate = self}

Related

how to add a pin with image when gesture on map

I would like to add a pin on the Map with an image on a gesture.
Actually the add pin on gesture feature works great but without the image because it has to be a MKAnnotationView and not just MKAnnotation.
So I got weird warnings that I'm unable to fix:
override func viewDidLoad() {
super.viewDidLoad()
let annotation = MKPointAnnotation()
annotation.title = location.title
annotation.coordinate = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
mapView.addAnnotation(annotation)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation { return nil }
let identifier = "CustomAnnotation"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView!.canShowCallout = false
annotationView?.backgroundColor = UIColor.clear
annotationView!.image = UIImage(named: "map-pinpoint.png")!
} else {
annotationView!.annotation = annotation
}
return annotationView
}
Maybe the errors are because MKPinAnnotationView always use a pin image, so you can't be override. You should use MKAnnotationView instead.

Custom image as annotation pin with two different colour images

I'm trying to add a custom image for my pin annotations as well as change the colour of the custom images for some of the annotations. The colour is changed. However, the image doesn't show up. The default pins show instead.
Here's my code:
class MyPointAnnotation : MKPointAnnotation {
var pinTintColor: UIColor?
}
class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate{
#IBOutlet weak var map: MKMapView!
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "myAnnotation") as? MKPinAnnotationView
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "myAnnotation")
annotationView?.canShowCallout = true
} else {
annotationView?.annotation = annotation
}
if annotation is MKUserLocation {
return nil
}
if let annotation = annotation as? MyPointAnnotation {
annotationView?.pinTintColor = annotation.pinTintColor
annotationView?.image = UIImage(named: "BLog.png")
}
return annotationView
}
override func viewDidLoad() {
super.viewDidLoad()
self.map.delegate = self
let annotation1 = MyPointAnnotation()
annotation1.coordinate = CLLocationCoordinate2DMake([LatArray], [LonArray])
annotation1.title = NameArray
annotation1.pinTintColor = .red
let annotation2 = MyPointAnnotation()
annotation2.coordinate = CLLocationCoordinate2DMake([LatArray2], [LonArray2])
annotation2.title = NameArray2
annotation2.pinTintColor = .green
}
}
The image "BLog.png" is located in the main bundle.
I've assigned the MKMapView as a delegate.
But the image still won't change.
You need to use MKAnnotationView instead of MKPinAnnotationView to add a custom image for your pin annotations.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
if // Image pin // {
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "image")
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "image")
annotationView?.canShowCallout = true
annotationView?.image = UIImage(named: "BLog.png")
let rightButton: AnyObject! = UIButton(type: UIButtonType.detailDisclosure)
annotationView?.rightCalloutAccessoryView = rightButton as? UIView
}
else {
annotationView?.annotation = annotation
}
return annotationView
} else {
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "myAnnotation") as? MKPinAnnotationView
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "myAnnotation")
annotationView?.canShowCallout = true
} else {
annotationView?.annotation = annotation
}
if let annotation = annotation as? MyPointAnnotation {
annotationView?.pinTintColor = annotation.pinTintColor
}
return annotationView
}
}

Custom Annotation Swift

I have created a map which contains a single annotation. From what I've seen, this is a very simple way of achieving this which I got off a tutorial. I am currently trying to get a custom picture as the annotation but am struggling to do so as almost all information on this topic is in objective C. Forgive me if it is really simple to do but I am relatively new to coding and would appreciate any help :)
class ViewController2: UIViewController {
#IBOutlet var Map: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//Location for first Pin
let locationOne = CLLocationCoordinate2DMake(-47.016945, 167.852095)
//Location for map centering
let locationNZ = CLLocationCoordinate2DMake(-43.937462, 170.507813)
let span = MKCoordinateSpanMake(9, 9)
let region = MKCoordinateRegion(center: locationNZ, span: span)
Map.setRegion(region, animated: true)
//Create annotation one
let annotation = MKPointAnnotation()
annotation.coordinate = locationOne
annotation.subtitle = "Park"
annotation.title = "Rakiura National Park"
//Add annotation to the map
Map.addAnnotation(annotation)}
I assume its a different image of the default pin you want?
I've used this answer from another question, check it out here
Custom pin image in annotationView in iOS
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
}
updating #Jonask's answer
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.isKind(of: MKUserLocation.self) else {
return nil
}
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
}

Setting custom image - MKPinAnnotationView - Swift 3

I'm using MapKit and I'm currently trying to set a custom pin annotation image on my pins. However, I'm having a hard time figuring out why it doesn't work. All of the other code is working perfectly, and when I try printing the frame of the image after setting it, it does show the correct dimensions for my "pinImage", so it seems to be able to set the image on the property.
Also, the delegate is set correctly, this is verified by setting a custom color on the default pin.
I've also tried using "pinImage.png", without luck. And since MKPinAnnotationView is a subclass of MKAnnotationView, I see no problem with why that should be the issue, and to be sure, I tried to use the MKAnnotationView also, without luck.
Here's my code:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if let annotation = annotation as? Pin {
let identifier = LocalConstants.pinIdentifier
var view: MKPinAnnotationView
if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView {
dequeuedView.annotation = annotation
view = dequeuedView
} else {
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.calloutOffset = CGPoint(x: -5, y: 5)
let detailButton = UIButton(type: .detailDisclosure) as UIView
view.rightCalloutAccessoryView = detailButton
//view.pinTintColor = Util.Colors.pluppPurple
}
view.image = UIImage(named: "pinImage")
return view
}
Thanks in advance!
The answer was indeed to use MKAnnotationView and not MKPinAnnotationView. I do not know what I messed up when trying it out yesterday. Final working copy below, for future reference:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if let annotation = annotation as? Pin {
let identifier = LocalConstants.pinIdentifier
var view: MKAnnotationView
if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) {
dequeuedView.annotation = annotation
view = dequeuedView
} else {
view = MKAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.calloutOffset = CGPoint(x: -5, y: 5)
view.tintColor = Util.Colors.pluppGrey
let detailButton = UIButton(type: .detailDisclosure) as UIView
view.rightCalloutAccessoryView = detailButton
}
view.image = UIImage(named: LocalConstants.pluppPin)
return view
}
return nil
}

Opening MapKit pin in Maps

I can't seem to get the final part of Ray Wenderlich's mapkit tutorial to work. I get the pins to display correctly but when I click on the pin, it doesn't open in Maps as I would like it too. Here is the link to the full tutorial (Link)
And here is my code:
import Foundation
import UIKit
import MapKit
import AddressBook
class CroquisMapView: UIViewController, MKMapViewDelegate {
var section : Int?
var index : Int?
#IBOutlet weak var mapView: MKMapView!
let regionRadius: CLLocationDistance = 1000
func centerMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
regionRadius * 2.0, regionRadius * 2.0)
mapView.setRegion(coordinateRegion, animated: true)
}
override func viewDidLoad() {
mapView.delegate = self
let coordenadas = croquisGruposArray[section!].items[index!].coordenadas
let coordenadasArray = coordenadas!.characters.split{$0 == ","}.map(String.init)
guard let lat = NSNumberFormatter().numberFromString(coordenadasArray[0])?.doubleValue,
let long = NSNumberFormatter().numberFromString(coordenadasArray[1])?.doubleValue else {
return
}
let initialLocation = CLLocation(latitude: lat, longitude: long)
let artwork = Artwork(title: "\(croquisGruposArray[section!].items[index!].descripcion!)",
locationName: "\(globalLigaNombre!)",
discipline: "Futbol",
coordinate: CLLocationCoordinate2D(latitude: lat, longitude: long))
mapView.addAnnotation(artwork)
centerMapOnLocation(initialLocation)
}
}
class Artwork: NSObject, MKAnnotation {
let title: String?
let locationName: String
let discipline: String
let coordinate: CLLocationCoordinate2D
init(title: String, locationName: String, discipline: String, coordinate: CLLocationCoordinate2D) {
self.title = title
self.locationName = locationName
self.discipline = discipline
self.coordinate = coordinate
super.init()
}
var subtitle: String? {
return locationName
}
func mapItem() -> MKMapItem {
let addressDictionary = [String(kABPersonAddressStreetKey): locationName]
let placemark = MKPlacemark(coordinate: coordinate, addressDictionary: addressDictionary)
let mapItem = MKMapItem(placemark: placemark)
mapItem.name = title
return mapItem
}
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!) {
print("CLICKED")
let location = view.annotation as! Artwork
let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]
location.mapItem().openInMapsWithLaunchOptions(launchOptions)
}
}
extension CroquisMapView {
// 1
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if let annotation = annotation as? Artwork {
let identifier = "pin"
var view: MKPinAnnotationView
if let dequeuedView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
as? MKPinAnnotationView { // 2
dequeuedView.annotation = annotation
view = dequeuedView
} else {
// 3
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.calloutOffset = CGPoint(x: -5, y: 5)
view.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure) as UIView
}
return view
}
return nil
}
}
Figured it out: I wasn't calling calloutAccessoryControlTapped in my main class. I added it and it with the code provided by Andrej:
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
let url = NSURL(string: "http://maps.apple.com/?q=\(lat),\(long)")
if UIApplication.sharedApplication().canOpenURL(url!) == true {
UIApplication.sharedApplication().openURL(url!)
}
}
You can try this:
let url = NSURL(string: "http://maps.apple.com/?q=44.33833,13.98131")
if UIApplication.sharedApplication().canOpenURL(url!) == true
{
UIApplication.sharedApplication().openURL(url!)
}
You can also do like this:
extension ViewController : MKMapViewDelegate {
func getDirections(){ // Here you can put everything, this function is calling when the user select the dialogue pin's bubble. I propose a code who open the application Map.
guard let selectedPin = selectedPin else { return }
let mapItem = MKMapItem(placemark: selectedPin)
let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]
mapItem.openInMapsWithLaunchOptions(launchOptions)
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView?{
guard !(annotation is MKUserLocation) else { return nil }
if annotation is MKUserLocation {
//return nil so map view draws "blue dot" for standard user location
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
}
pinView?.pinTintColor = UIColor.orangeColor()
pinView?.canShowCallout = true
let smallSquare = CGSize(width: 30, height: 30)
let button = UIButton(frame: CGRect(origin: CGPointZero, size: smallSquare))
button.setBackgroundImage(UIImage(named: "car"), forState: .Normal)
button.addTarget(self, action: #selector(self.getDirections), forControlEvents: .TouchUpInside)
pinView?.leftCalloutAccessoryView = button
return pinView}
}