How to Set Up Array for Multi Annotations with Swift

how to set up array for multi annotations with swift

You could do, for example:

let locations = [
["title": "New York, NY", "latitude": 40.713054, "longitude": -74.007228],
["title": "Los Angeles, CA", "latitude": 34.052238, "longitude": -118.243344],
["title": "Chicago, IL", "latitude": 41.883229, "longitude": -87.632398]
]

for location in locations {
let annotation = MKPointAnnotation()
annotation.title = location["title"] as? String
annotation.coordinate = CLLocationCoordinate2D(latitude: location["latitude"] as! Double, longitude: location["longitude"] as! Double)
mapView.addAnnotation(annotation)
}

Or, alternatively, use a custom type, e.g.:

struct Location {
let title: String
let latitude: Double
let longitude: Double
}

let locations = [
Location(title: "New York, NY", latitude: 40.713054, longitude: -74.007228),
Location(title: "Los Angeles, CA", latitude: 34.052238, longitude: -118.243344),
Location(title: "Chicago, IL", latitude: 41.883229, longitude: -87.632398)
]

for location in locations {
let annotation = MKPointAnnotation()
annotation.title = location.title
annotation.coordinate = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
mapView.addAnnotation(annotation)
}

Or you can replace that for loop with map:

let annotations = locations.map { location -> MKAnnotation in
let annotation = MKPointAnnotation()
annotation.title = location.title
annotation.coordinate = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
return annotation
}
mapView.addAnnotations(annotations)

How to setup multiple annotations near the same area

simple way would be adding the annotations in an array and then looping through the array and adding the annotations on the map. Also you need to adjust the zoom level of the map.

let locations = [
["title": "New York, NY", "latitude": 40.713054, "longitude": -74.007228],
["title": "Los Angeles, CA", "latitude": 34.052238, "longitude": -118.243344],
["title": "Chicago, IL", "latitude": 41.883229, "longitude": -87.632398]
]

for location in locations {
let annotation = MKPointAnnotation()
annotation.title = location["title"] as? String
annotation.coordinate = CLLocationCoordinate2D(latitude: location["latitude"] as! Double, longitude: location["longitude"] as! Double)
mapView.addAnnotation(annotation)
}

display multiple annotations on mapview

This should work for you.

By the way, looping through your locations whilst in the events loop is just going to add duplicates of the same pin, which will be very bad on memory and it's not a good thing to do.

import UIKit
import MapKit
import Firebase

class ViewController: UIViewController, MKMapViewDelegate {

@IBOutlet weak var map: MKMapView!

let locationManager = CLLocationManager()

var events = Array<Event>()

var locations = Array<Location>()

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

locationManager.requestWhenInUseAuthorization()

locationManager.startUpdatingLocation()

locationManager.desiredAccuracy = kCLLocationAccuracyBest

// This closure gets called once for every event in your database
getEvents { (event, pin) in

self.tableView.reloadData()

if event != nil && pin != nil {

print(event!)

self.locations.append(pin!)

self.events.append(event!)

} else {

print("Failed to get event.")
}
}
}

func getEvents(results: @escaping (_ event: Event?, _ pin:Location?)->()) {

let ref = FIRDatabase.database().reference().child("Events")

ref.observe(.childAdded, with: { (snapshot) in

guard let value = snapshot.value as? Dictionary<String,String> else { return }

guard let name = value["eventName"],
let location = value["location"],
let attending = value["attendance"],
let dateTime = value["dateTime"],
let addedByUser = value["addedByUser"] else { return }

self.getEventPlacemark(address: location, results: { (placemark) in

if let placemark = placemark {

let pin = Location(title: name, coordinate: placemark.coordinate)

var distance: Double = -1 // If user location is not avalible, this will stay at -1

if let currentLocation = self.locationManager.location?.coordinate {

distance = pin.coordinate.distance(to: currentLocation)
}

let event = Event(id: snapshot.key, name: name, location: location, dateTime: dateTime, addedByUser: addedByUser, attending: attending, distance: distance)

results(event, pin)

return
}
})
})
}

func getEventPlacemark(address:String, results: @escaping (_ placemark: MKPlacemark?)->()){

let geocoder = CLGeocoder()

geocoder.geocodeAddressString(address) { (placemarks, error) in

if let error = error {

print(error.localizedDescription)

results(nil)
}

if let placemark = placemarks?.first {

results(MKPlacemark(placemark: placemark))
}
}
}

func displayAllEvents(){

self.map.addAnnotations(self.locations)
}

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

if let userLocation = annotation as? MKUserLocation {

let view = (mapView.dequeueReusableAnnotationView(withIdentifier: "userLocationPin") as? MKPinAnnotationView) ?? MKPinAnnotationView(annotation: userLocation, reuseIdentifier: "userLocationPin")

view.pinTintColor = .purple

view.canShowCallout = true

return view
}

if let pin = annotation as? MKPointAnnotation {

let view = (mapView.dequeueReusableAnnotationView(withIdentifier: "pin") as? MKPinAnnotationView) ?? MKPinAnnotationView(annotation: pin, reuseIdentifier: "pin")

view.pinTintColor = .red

view.canShowCallout = true

return view
}

return nil
}
}

class Location: NSObject, MKAnnotation {

var title: String?

var coordinate: CLLocationCoordinate2D

init(title: String, coordinate: CLLocationCoordinate2D) {

self.title = title

self.coordinate = coordinate
}
}

struct Event {

var name: String

var location: String
}

extension CLLocationCoordinate2D {

func distance(to: CLLocationCoordinate2D) -> CLLocationDistance {

return MKMetersBetweenMapPoints(MKMapPointForCoordinate(self), MKMapPointForCoordinate(to))
}
}

If you are going to implement my code above, you'll need to remove your code from

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])

because you don't need to add the pin manually anymore.

Can you try putting this in your view did load function and not have anything else run. This should put a pin to the west of Africa.

Something to notice, if the coordinate is
CLLocationCoordinate2D(latitude: 0, longitude: 0), the pin appears
right down at Antartica on the date line, which is the bottom right of
the map. So if for some reason your coordinate is the default 0,0,
your pins might by sitting there.

let pin = MKPointAnnotation()

pin.title = "Null Island"

pin.coordinate = CLLocationCoordinate2DMake(0.000001, 0.000001)

self.map.addAnnotation(pin)

This could possibly be where your pins are.

Sample Image

How can I create multiple custom annotations in a map view?

It's been a long time since I've used an MKMapView and custom annotations (it was in Objective-C.)

I seem to remember that in your mapView(_:viewFor:) function you need to test to see if the annotation being passed to you is an MKUserLocation. If it is, return nil:

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !annotation is MKUserLocation else {
//This is the user location. Return nil so the system uses the blue dot.
return nil
}
//Your code to create an return custom annotations)
}

Dealing with multiple annotations at the same address in an MGLMapView using SwiftUI and Mapbox

I ended up doing my own implementation--I made an array of annotations with the same latitude and longitude and then I added buttons to the custom callout to cycle through that array, keeping track of the annotation that I am looking at.

How to add multiple annotations in map view

You can do it by manipulating MKMapView's delegate

func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
print("viewForAnnotation \(annotation.title)")
if annotation is MKUserLocation {
return nil
}
let reuseID = "pin"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseID) as? MKPinAnnotationView
if(pinView == nil) {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseID)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
}
return pinView
}


Related Topics



Leave a reply



Submit