I managed to make my annotations with a personalized image by annotation and the title in the popup.
My question: Is it possible to also add the title below the annotation?
Thank you in advance for your feedback.
The view controller
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
let pageDecouverte = listeDesPoints[view.tag]
selectedLieuDecouverte = pageDecouverte
self.performSegue(withIdentifier: "showPageDecouverte", sender: nil)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
{
if !(annotation is MKPointAnnotation) {
return nil
}
let annotationIdentifier = "location"
var annotationView = carteRegion.dequeueReusableAnnotationView(withIdentifier: (annotationIdentifier))
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
annotationView!.canShowCallout = true
}
else {
annotationView!.annotation = annotation
}
if annotation is MyAnnotation {
let imageName = (annotation as! MyAnnotation).imageName
annotationView?.tag = (annotation as! MyAnnotation).tag
if imageName != nil{
let interetImage = UIImage(named: imageName!)
annotationView!.image = interetImage
}
}
annotationView?.clusteringIdentifier = annotationIdentifier
annotationView?.canShowCallout = true
annotationView?.rightCalloutAccessoryView = UIButton(type:.detailDisclosure)
return annotationView
}
}
For my MyAnnotation
import UIKit
import MapKit
import Parse
class MyAnnotation: MKPointAnnotation {
var imageName: String?
var annotationTitle: String?
var tag : Int = 0
var pageDecouverte:PFPageDecouverte?
}
Instead of MKAnnotationView use the subclass MKMarkerAnnotationView to render the title below the marker.
Also in MyAnnotation rename annotationTitle to title, then MKMarkerAnnotationView automatically knows what to render.
See the definition of protocol MKAnnotation to see why.
Related
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
}
}
I customized my callOutView, creating an own AnnotationView theGreatAnnotationView, but I want to keep the standard Annotation Pin on the map. In this code I use a custom annotation image view?.image = annotation.image but when is delete the line, there is no annotation on my map. Can you help me solving this problem?
func mapView(_ surroundingMapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
var annoView: MKAnnotationView?
if annotation.isKind(of: MKUserLocation.self) {
return nil
}
var view = surroundingMapView.dequeueReusableAnnotationView(withIdentifier: "imageAnnotation")
if view == nil {
view = theGreatAnnotationView(annotation: annotation, reuseIdentifier: "imageAnnotation")
reuseIdentifier: "imageAnnotation")
view!.canShowCallout = false
}
let annotation = annotation as! Artwork
view?.image = annotation.image
view?.annotation = annotation
return view
}
You should use MKPinAnnotationView instead of MKAnnotationView.
func mapView(_ surroundingMapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
var annoView: MKAnnotationView?
if annotation.isKind(of: MKUserLocation.self) {
return nil
}
if /* if annotation is image */ {
var view = surroundingMapView.dequeueReusableAnnotationView(withIdentifier: "imageAnnotation")
if view == nil {
view = theGreatAnnotationView(annotation: annotation, reuseIdentifier: "imageAnnotation")
view!.canShowCallout = false
}
let annotation = annotation as! Artwork
view?.image = annotation.image
view?.annotation = annotation
} else {
/* if annotation is pin */
var view = surroundingMapView.dequeueReusableAnnotationView(withIdentifier: "pinAnnotation")
if view == nil {
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "pinAnnotation")
view!.canShowCallout = false
}
let annotation = annotation as! Artwork
view?.annotation = annotation
}
return view
}
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
}
I have tried following different tutorials to make my MKAnnotations have an accessory item that will segue to a different page when clicked; however, I cannot get the item to show. Here is the code I've come up with after reviewing different sources:
extension MapController : MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "PlaceAnnotation"
if annotation is PlaceAnnotation {
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView!.canShowCallout = true
} else {
annotationView!.annotation = annotation
}
annotationView!.leftCalloutAccessoryView = nil
annotationView!.rightCalloutAccessoryView = UIButton(type: UIButtonType.detailDisclosure)
return annotationView
}
return nil
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
let place = view.annotation as! PlaceAnnotation
let placeName = place.title
print(placeName!)
let placeInfo = place.placeObject
let ac = UIAlertController(title: placeInfo?.title, message: placeInfo?.description, preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
}
}
Then, to create the annotation, I have this:
for place in places {
let placeCoord = CLLocationCoordinate2D(latitude: CLLocationDegrees(place.latitude)!, longitude: CLLocationDegrees(place.longitude)!)
let annotation = PlaceAnnotation(title: place.title, coordinate: placeCoord, placeObject: place)
mapView.addAnnotation(annotation)
}
And the PlaceAnnotation class is as follows:
class PlaceAnnotation: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String?
var placeObject: Location?
init(title: String, coordinate: CLLocationCoordinate2D, placeObject: Location) {
self.title = title
self.coordinate = coordinate
self.placeObject = placeObject
}
}
The only thing that displays on the annotation when clicked is the Title, but nothing else. I appreciate any help, thank you very much!
(I am working in Swift 3)
I tried your code and it works perfectly fine for me.
But when I removed say,
mapView.delegate = self
Accessory item did not show up, because the delegate is not called.
I am creating a map application which allows emojis to be attached to locations. Currently, the image is displayed above the stock apple map annotation.
I wish to hide the stock pin image while still displaying the selected emoji by the user. Is this possible?
I have this code so far to perform this:
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
//let identifier = "MyPin"
if annotation.isKindOfClass(MKUserLocation) {
return nil
}
let dictName = arrLocation[((annotation as? MyAnnotation)?.index)!]
let imgName = dictName.valueForKey("pin_img") as? String
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(imgName!)
if annotationView == nil
{
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: imgName)
annotationView!.canShowCallout = false
let name = dictName.valueForKey("name") as! String
let annot = MyAnnotation(titleName:name)
annotationView?.annotation = annot
}
else
{
annotationView!.annotation = annotation
}
let detailButton: UIButton = UIButton(type: UIButtonType.Custom)
// size and placement of emoji on map
detailButton.frame = CGRectMake(-34,-25,85,85)
detailButton.tag = ((annotation as? MyAnnotation)?.index)!
detailButton.addTarget(self, action:"emojiTap:", forControlEvents: UIControlEvents.TouchUpInside)
detailButton.setBackgroundImage(UIImage(named:(dictName.valueForKey("pin_img") as? String)!), forState: UIControlState.Normal)
annotationView!.addSubview(detailButton)
return annotationView
}
Custom annotation view
Instead of using an MKPinAnnotationView, use its superclass MKAnnotationView.
Responding to input
To respond to the user tapping on an annotation implement the mapView:didSelectAnnotation: delegate method. This delegate method is called when the annotation is tapped.
Note that you do not need to use the button inside the annotation view. This means the functionality in emojiTap: must be implemented by the mapView:didSelectAnnotationMethod:.
Example
Combining these
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation.isKindOfClass(MKUserLocation) {
return nil
}
let dictName = arrLocation[((annotation as? MyAnnotation)?.index)!]
let imgName = dictName.valueForKey("pin_img") as? String
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(imgName!)
if annotationView == nil
{
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: imgName)
let name = dictName.valueForKey("name") as! String
let annot = MyAnnotation(titleName:name)
annotationView?.annotation = annot
}
else
{
annotationView!.annotation = annotation
}
annotationView!.canShowCallout = false
return annotationView
}
func mapView(_ mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
guard let annotation = view.annotation as? MyAnnotation else {
return
}
print("tapped annotation: \(annotation.index)
// Implement the code from emojiTap: here.
}