2

I have a parsed a set of data from a JSON file (see example below):

{
    "locations": [

        {
            "id": "0001",
            "name": "Helensburgh Tunnels",
            "type": "Tunnels, Beach, Views",
            "location": "Helensburgh, South Coast",
            "image": "Helensburgh-Tunnels.jpg",
            "activity": "Walking, photography, tunnelling",
            "isVisited": false,
            "latitude": -34.178985,
            "longitude": 150.992867
        }
    ]
}

I am able to correctly read all of this data into a TableView (everything works correctly), however, I would also like to display all of the locations within the JSON file as annotations on a MapView. So far, everything appears correctly except for a preview image on the left side of the callout box (all the annotation pins appear, when clicked they show a callout with a title and subtitle, but no image).

What do I need to resolve so that I can show this image? I am able to achieve it in other sections of my app, where only one location is shown, however, I cannot seem to figure out how to add images to all the annotation callouts within this view.

enter image description here

This is the code I am using to populate the annotations in my NearMeMapViewController:

import UIKit
import MapKit
import CoreLocation

class NearMeMapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {

    @IBOutlet var nearMeMap: MKMapView!

    let locationManager = CLLocationManager()

    var locations = [Location]()
    var location:Location!

    override func viewDidLoad() {
        super.viewDidLoad()

        // parse json
        if let locationJson = readLocation(){
            if let locationArray = locationJson["locations"] as? [[String:Any]]{
                for location in locationArray{
                    locations.append(Location.init(locationInfo: location))
                }
                print(locations.count)
            }
        }
        // end parse json

        nearMeMap.delegate = self

        self.locationManager.delegate = self
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.locationManager.requestWhenInUseAuthorization()
        self.locationManager.startUpdatingLocation()
        self.nearMeMap.showsUserLocation = true

        // Show annotation
        for location in locations {
            let annotation = MKPointAnnotation()
            annotation.title = location.name
            annotation.subtitle = location.type
            annotation.coordinate = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
            nearMeMap.addAnnotation(annotation)

        }

    }


    // Start test - Custom annotation callout with image
    func nearMeMap (_ nearMeMap: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {

        let identifier = "MyPin"

        if annotation.isKind(of: MKUserLocation.self) {
        return nil
        }

        // Reuse the annotation if possible
        var annotationView:MKPinAnnotationView? = nearMeMap.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView

        if annotationView == nil {
            annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
            annotationView?.canShowCallout = true
        }

        let leftIconView = UIImageView(frame: CGRect.init(x: 0, y: 0, width: 53, height: 53))
        leftIconView.image = UIImage(named: location.image)
        annotationView?.leftCalloutAccessoryView = leftIconView

        return annotationView
    }
    // End test

I would really appreciate any help! I'm a student and I'm just learning, so sorry if I've used any incorrect terminology or there are noob mistakes.

joshlorschy
  • 105
  • 1
  • 2
  • 15

2 Answers2

3

Swift 3.0

On above code the MKMapViewDelegate should be

func mapView (_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?{...}

and not

func nearMeMap (_ nearMeMap: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {...}

Add var currentIndex = 0 as global declaration to identify the current image index. else, you aware to use id from JSON response.

i.e., Global Scope becomes like below code,

let locationManager = CLLocationManager()

var locations = [Location]()
//test variable? implemented to resolve issue with images in custom callout
var location:Location!

var currentIndex = 0
override func viewDidLoad() {...}

Then, the leftIconView will becomes,

let leftIconView = UIImageView(frame: CGRect.init(x: 0, y: 0, width: 53, height: 53))

var images = [String]()
for location in locations{
    images.append(location.image)
}
leftIconView.image = UIImage(named: images[currentIndex])
self.currentIndex = self.currentIndex+1 //0,1,2,3...N.

Output:-

enter image description here

Rajamohan S
  • 7,229
  • 5
  • 36
  • 54
0

when you want to set custom image for annotation view, prefer MKAnnotationView instead of an MKPinAnnotationView. You can set your custom image as annotation by setting it as Image attribute of MKAnnotationView . Check here for more info on MKAnnotationView .

As MKPinAnnotationView is a subclass of MKAnnotationView, it has an image property but it generally (usually when you don't expect it) ignores it and displays its built-in pin image instead.

So it's best to just use a plain MKAnnotationView.

See this answer for more details.You can use MKAnnotationView as explained here.

----- EDIT -----

hide your basic Callout to show your custom image.

 annotationView?.canShowCallout = false

Refer this ans to customize CallOut images. Check this link for the detailed tutorial.

Hope it helps. Happy Coding!!

luckyShubhra
  • 2,731
  • 1
  • 12
  • 19
  • If you read the question, he isn't trying to change the pin image, but rather have an image on the callout view. – Tristan Beaton Jun 29 '17 at 03:45
  • Ok, I misunderstood. I got your point @TristanBeaton. I will leave the ans in case any one needs in future. Thanks. – luckyShubhra Jun 29 '17 at 03:49
  • in your nearMeMap comment out annotationView?.canShowCallout = true. Can't try the same as I am away from my system. Btw I have also added a link for your reference. Hope it helps. – luckyShubhra Jun 29 '17 at 04:04
  • Check this link for well explained tutorial. http://sweettutos.com/2016/03/16/how-to-completely-customise-your-map-annotations-callout-views/ – luckyShubhra Jun 29 '17 at 04:08
  • You can also have a look at Rob's ans [here](https://stackoverflow.com/questions/17772108/custom-mkannotation-callout-bubble-with-button/17772487#17772487). He has explained 3 diffrerent ways to create custom callout view. – luckyShubhra Jun 29 '17 at 04:21