I am working with Google Map for IOS .Where i have implemented clustering but cluster and cluster item marker click event not work . But individual google map marker click event is working .
Here is my full code
import UIKit
import GoogleMaps
import Alamofire
import SwiftyJSON
let kCameraLatitude = 22.3475
let kCameraLongitude = 91.8123
/// Point of Interest Item which implements the GMUClusterItem protocol.
class POIItem: NSObject, GMUClusterItem {
var position: CLLocationCoordinate2D
var currencies = "currencies";
var phone = "phone";
var dateTime = "dateTime";
var location = "location";
var link = "link";
var exchangeLimits = "exhangeLimits";
var id = "id";
var updated_at = "updated";
var operationName = "opeationName";
var email = "email";
var address = "address";
var createdAt = "createdAt";
var workingDays = "workingDays";
var longitude = "longitude";
var latitude = "latitude";
var exchange = "exChange";
init(position: CLLocationCoordinate2D, operationName: String) {
self.position = position
self.operationName = operationName
}
}
class FirstViewController: UIViewController , GMUClusterManagerDelegate, GMSMapViewDelegate{
private var mapView: GMSMapView!
private var clusterManager: GMUClusterManager!
override func loadView() {
let camera = GMSCameraPosition.camera(withLatitude: kCameraLatitude,
longitude: kCameraLongitude, zoom: 6)
mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
mapView.delegate = self
self.view = mapView
}
override func viewDidLoad() {
super.viewDidLoad()
// Set up the cluster manager with default icon generator and renderer.
let iconGenerator = GMUDefaultClusterIconGenerator()
let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
let renderer = GMUDefaultClusterRenderer(mapView: mapView, clusterIconGenerator: iconGenerator)
clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer)
getAllMapsData()
clusterManager.cluster()
// Register self to listen to both GMUClusterManagerDelegate and GMSMapViewDelegate events.
clusterManager.setDelegate(self, mapDelegate: self)
}
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
print("You tapped at \(coordinate.latitude), \(coordinate.longitude)")
var alert = UIAlertController(title: "Choose Media type" , message: "post any" , preferredStyle: .actionSheet);
var photos = UIAlertAction(title : "Photos" , style: .default , handler: nil)
var videos = UIAlertAction(title : "Videos" , style: .default , handler: nil)
var cancel = UIAlertAction(title : "Calcel" , style: .default , handler: nil)
alert.addAction(photos)
alert.addAction(videos)
alert.addAction(cancel)
present(alert, animated: true , completion: nil)
}
// MARK: - GMUClusterManagerDelegate
func clusterManager(clusterManager: GMUClusterManager, didTapCluster cluster: GMUCluster) {
let newCamera = GMSCameraPosition.camera(withTarget: cluster.position,
zoom: mapView.camera.zoom + 1)
let update = GMSCameraUpdate.setCamera(newCamera)
mapView.moveCamera(update)
}
// MARK: - GMUMapViewDelegate
func mapView(mapView: GMSMapView, didTapMarker marker: GMSMarker) -> Bool {
if let poiItem = marker.userData as? POIItem {
NSLog("Did tap marker for cluster item \(poiItem.operationName)")
print("clicked cluster")
} else {
NSLog("Did tap a normal marker")
print("clicked marker")
}
return false
}
var allDataList = [[String:AnyObject]]()
public func getAllMapsData(){
Alamofire.request("http://coinatmfinder.com/getDatas").responseJSON { response in
if let JSON = response.result.value {
self.allDataList = JSON as! [[String : AnyObject]]
for eachData in self.allDataList {
//let allDataModel = AllDataModel()
// allDataModel.address = eachData["address"] as! String
var operatorName = eachData["operatorName"]
var lat = eachData["latitude"]
var latDouble = 0.0;
if let lats = lat {
latDouble = (lats as! NSString).doubleValue
}
var longs = eachData["longitude"]
var longsDouble = 0.0;
if let longs = longs {
longsDouble = (longs as! NSString).doubleValue
}
let item = POIItem(position: CLLocationCoordinate2DMake(latDouble, longsDouble), operationName: operatorName as! String)
self.clusterManager.add(item)
}
print("JSON: \(self.allDataList)")
}
}
}
}
Was working on this today and also tried the same function and found it wasn't working because it was the wrong one. Instead of:
func clusterManager(clusterManager: GMUClusterManager, didTapCluster cluster: GMUCluster) {
let newCamera = GMSCameraPosition.camera(withTarget: cluster.position,
zoom: mapView.camera.zoom + 1)
let update = GMSCameraUpdate.setCamera(newCamera)
mapView.moveCamera(update)
}
Try this one: (it looks almost the same as the one above except it has a return type of Bool).
func clusterManager(_ clusterManager: GMUClusterManager, didTap cluster: GMUCluster) -> Bool {
let newCamera = GMSCameraPosition.camera(withTarget: cluster.position,
zoom: mapView.camera.zoom + 1)
let update = GMSCameraUpdate.setCamera(newCamera)
mapView.moveCamera(update)
return false
}
(Using Swift 3)
Related
When I add the annotations to the map they sometimes show and sometimes not depending on how close they are to each other. If they are in the same house lets say one won't show. How do I make both of them show? Do I need to make a custom annotation class? I heard ios11 has a clumping feature, do I need to use that? Here is the code(abridged):
import UIKit
import MapKit
import Firebase
class GameViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
fileprivate var locations = [CLLocation]()
fileprivate var userLocations = [(loc: CLLocation, name: String, team: String)]()
fileprivate var userAnnotations = [MKAnnotation]()
fileprivate var hasBeenUP = false
var ref: FIRDatabaseReference!
let uid = FIRAuth.auth()!.currentUser!.uid
var timer = Timer()
var timeLeft = 0.0
var firstTimer = Timer()
var name = ""
var team = ""
override func viewDidLoad() {
super.viewDidLoad()
let center = CLLocationCoordinate2D(latitude: 47.786769, longitude: -20.413634)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
self.mapView.setRegion(region, animated: true)
mapView.mapType = .hybrid
locationManager.startUpdatingLocation()
ref = FIRDatabase.database().reference()
setupULSending()
getMetaInfo()
ref.child("realtimeLocations").observe(FIRDataEventType.value, with: { (snapshot) in
self.userLocations = []
for rest in snapshot.children.allObjects as! [FIRDataSnapshot] {
guard let snapshotValue = snapshot.value as? NSDictionary, let snapVal = snapshotValue[rest.key] as? NSDictionary else {
break
}
let name = snapVal["name"] as! String
let team = snapVal["team"] as? String ?? ""
if let lat = snapVal["lat"] as? Double,
let long = snapVal["long"] as? Double {
let location = CLLocation(latitude: lat, longitude: long)
self.userLocations.append((loc: location, name: name, team: team))
}else {
}
}
DispatchQueue.main.async {
self.updateUserLocation()
}
})
}
private lazy var locationManager: CLLocationManager = {
let manager = CLLocationManager()
manager.allowsBackgroundLocationUpdates = true
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.delegate = self
manager.requestAlwaysAuthorization()
return manager
}()
func updateUserLocation() {
for an in self.mapView.annotations {
mapView.removeAnnotation(an)
}
for loc in userLocations {
let annotation = MKPointAnnotation()
annotation.coordinate = loc.loc.coordinate
annotation.title = loc.name
annotation.subtitle = "local"
mapView.addAnnotation(annotation)
}
}
}
// MARK: - CLLocationManagerDelegate
extension GameViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations
locations: [CLLocation]) {
let location = locations.last as! CLLocation
self.locations.append(location)
}
}
On the MKAnnotationView, you have to set the MKFeatureDisplayPriority to 'required'. You can modify the annotation views by implementing MKMapViewDelegate and mapView(MKMapView, viewFor: MKAnnotation). Something like this:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation { return nil }
var view = mapView.dequeueReusableAnnotationView(withIdentifier: "yourIdentifier")
if view == nil {
view = MKMarkerAnnotationView(annotation: nil, reuseIdentifier: "yourIdentifier")
}
view?.displayPriority = .required
return view
}
More options for this are explained in the WWDC 2017 video 237 "What's New in MapKit"
I'm developing an app on which I want to show a lot of events on the map. The user can click on an event and see a lot of informations about it.
In another view, a user can create a new event then the location and title are stored in Firebase database.
Then when others users watch the GoogleMaps on my app, they are able to see all the events who are a marker in the map.
I want to cluster the markers from Firebase when the user zoom out on the map but it can't work maybe because of my loaded way of the data markers on Firebase.
There's 3 issues:
- I'm not able to cluster my custom marker with orange color.
- The markers and the clusters icon don't appear when the map load, I need to zoom in or zoom out first
- I want the data of marker are show in the infoWindow but I got to use the right data for the marker corresponding on the GoogleMap and Firebase.
- When I click on a cluster icon, it shows the alertController too, but I want only see the alertController when user tap a marker not on the cluster icon.
Here's my current code :
class POIItem: NSObject, GMUClusterItem {
var position: CLLocationCoordinate2D
var name: String!
init(position: CLLocationCoordinate2D, name: String) {
self.position = position
self.name = name
}
}
class NewCarteViewController: UIViewController, GMSMapViewDelegate, CLLocationManagerDelegate, GMUClusterManagerDelegate {
var locationManager = CLLocationManager()
var positionActuelle = CLLocation() // Another current position
var currentPosition = CLLocationCoordinate2D()
var latiti: CLLocationDegrees!
var longiti: CLLocationDegrees!
private var clusterManager: GMUClusterManager! // Cluster
private var maMap: GMSMapView!
var marker = GMSMarker()
let geoCoder = CLGeocoder()
var ref = DatabaseReference()
var estTouche: Bool!
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
positionActuelle = locationManager.location!
latiti = positionActuelle.coordinate.latitude
longiti = positionActuelle.coordinate.longitude
currentPosition = CLLocationCoordinate2D(latitude: latiti, longitude: longiti)
let camera = GMSCameraPosition.camera(withTarget: currentPosition, zoom: 10)
maMap = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
maMap.mapType = .normal
maMap.settings.compassButton = true
maMap.isMyLocationEnabled = true
maMap.settings.myLocationButton = true
maMap.delegate = self
self.view = maMap
let iconGenerator = GMUDefaultClusterIconGenerator()
let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
let renderer = GMUDefaultClusterRenderer(mapView: maMap, clusterIconGenerator: iconGenerator)
clusterManager = GMUClusterManager(map: maMap, algorithm: algorithm, renderer: renderer)
loadMarker()
}
// Download datas of markers from Firebase Database
func loadMarker() {
ref = Database.database().reference()
let usersRef = ref.child("markers")
usersRef.observeSingleEvent(of: .value, with: { (snapshot) in
if (snapshot.value is NSNull) {
print("not found")
} else {
for child in snapshot.children {
let userSnap = child as! DataSnapshot
let uid = userSnap.key // the uid of each user
let userDict = userSnap.value as! [String: AnyObject]
let latitudes = userDict["latitudeEvent"] as! Double
let longitudes = userDict["longitudeEvent"] as! Double
let bellname = userDict["nom"] as! String
let belltitre = userDict["titreEvent"] as! String
let total = snapshot.childrenCount // Number of markers in Firebase
let positionMarker = CLLocationCoordinate2DMake(latitudes, longitudes)
var diff = Double(round(100*self.getDistanceMetresBetweenLocationCoordinates(positionMarker, coord2: self.currentPosition))/100)
var dif = Double(round(100*diff)/100)
var positionEvenement = CLLocation(latitude: latitudes, longitude: longitudes) // Event location
// Function in order to convert GPS Coordinate in an address
CLGeocoder().reverseGeocodeLocation(positionEvenement, completionHandler: {(placemarks, error) -> Void in
if error != nil {
print("Reverse geocoder a rencontré une erreur " + (error?.localizedDescription)!)
return
}
if (placemarks?.count)! > 0 {
print("PlaceMarks \(placemarks?.count)!")
let pm = placemarks?[0] as! CLPlacemark
var adres = "\(pm.name!), \(pm.postalCode!) \(pm.locality!)"
let item = POIItem(position: CLLocationCoordinate2DMake(latitudes, longitudes), name: "")
// self.marker.userData = item // I delete this line
self.clusterManager.add(item)
self.marker = GMSMarker(position: positionMarker)
self.marker.icon = UIImage(named: "marker-45")
self.marker.title = "\(belltitre)"
self.marker.snippet = "Live de \(bellname)\nLieu: \(adres)\nDistance: \(dif) km"
self.marker.map = self.maMap
} else {
print("Problème avec les données reçu par le géocoder")
}
})
}
self.clusterManager.cluster()
self.clusterManager.setDelegate(self, mapDelegate: self)
}
})
}
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
if let poiItem = marker.userData as? POIItem {
NSLog("Did tap marker for cluster item \(poiItem.name)")
} else {
NSLog("Did tap a normal marker")
}
return false
}
func clusterManager(_ clusterManager: GMUClusterManager, didTap cluster: GMUCluster) -> Bool {
let newCamera = GMSCameraPosition.camera(withTarget: cluster.position, zoom: maMap.camera.zoom + 1)
let update = GMSCameraUpdate.setCamera(newCamera)
maMap.moveCamera(update)
return false
}
func renderer(_ renderer: GMUClusterRenderer, markerFor object: Any) -> GMSMarker? {
let marker = GMSMarker()
if let model = object as? POIItem { // POIItem class is your MarkerModel class
marker.icon = UIImage(named: "marker-45") // Like this ?
// set image view for gmsmarker
}
return marker
}
// Distance between 2 locations
func getDistanceMetresBetweenLocationCoordinates(_ coord1: CLLocationCoordinate2D, coord2: CLLocationCoordinate2D) -> Double {
let location1 = CLLocation(latitude: coord1.latitude, longitude: coord1.longitude)
let location2 = CLLocation(latitude: coord2.latitude, longitude: coord2.longitude)
var distance = ((location1.distance(from: location2)) / 1000)
return distance
}
// Affiche les boutons du live
func alert(_ sender: AnyObject) {
let alertController = UIAlertController(title: "", message: "", preferredStyle: .actionSheet)
alertController.title = nil
alertController.message = nil
alertController.addAction(UIAlertAction(title: "Accéder au live", style: .default, handler: self.accederLive))
alertController.addAction(UIAlertAction(title: "Infos event", style: .default, handler: self.infosEvent))
alertController.addAction(UIAlertAction(title: "Annuler", style: .cancel, handler: nil))
self.present(alertController, animated: true, completion: nil)
}
// Display infoWindow and alertController
func mapView(_ mapView: GMSMapView!, markerInfoWindow marker: GMSMarker!) -> UIView! {
let infoWindow = Bundle.main.loadNibNamed("InfoWindow", owner: self, options: nil)?.first! as! CustomInfoWindow
self.estTouche = true
if self.estTouche == true {
self.alert(self.estTouche as AnyObject)
} else {
print("estTouche est false")
}
print(self.estTouche)
return nil // infoWindow
}
Sorry it a lil bit long code if you don't understand something let me know, I tried to comment
Here's the screenshot of the googlemap now.
The first screenshot is when I open the map, you can see nothing appears on the map, no cluster icon or isolate marker, it strange.
The second screenshot is when I zoom in one time, so after cluster icon appears and one marker appears too.
What's wrong with my code, I want all cluster icon or marker show when user open the map view.
Firstly loadMarker() should be called after the clusterManager is initialized i.e
clusterManager = GMUClusterManager(map: maMap, algorithm: algorithm, renderer: renderer)
then
clusterManager.cluster()
clusterManager.setDelegate(self, mapDelegate: self)
should be placed in loadMarker() after for loop ends.
Your viewcontroller should conform to this protocol GMUClusterManagerDelegate then add these 2 methods in viewcontroller.
func renderer(_ renderer: GMUClusterRenderer, markerFor object: Any) -> GMSMarker? {
let marker = GMSMarker()
if let model = object as? MarkerModel {
// set image view for gmsmarker
}
return marker
}
func clusterManager(_ clusterManager: GMUClusterManager, didTap cluster: GMUCluster) -> Bool {
let newCamera = GMSCameraPosition.camera(withTarget: cluster.position, zoom: mapView.camera.zoom + 1)
let update = GMSCameraUpdate.setCamera(newCamera)
mapView.moveCamera(update)
return false
}
Try this and let me know if this works else we will try something else.
I resolve my question so I post here the solution, thank to Prateek for his help.
I use this topic for solve it too : How to implement GMUClusterRenderer in Swift
First I changed one line of code in a GoogleMaps files SDK:
I found it in my project at this path : Pods/Pods/Google-Maps-iOS-Utils/Clustering/GMUDefaultClusterRenderer.m
This file name is GMUDefaultClusterRenderer.m.
This changement it's for cluster custom marker icon in the cluster
- (void)renderCluster:(id<GMUCluster>)cluster animated:(BOOL)animated {
...
GMSMarker *marker = [self markerWithPosition:item.position
from:fromPosition
userData:item
clusterIcon:[UIImage imageNamed:#"YOUR_CUSTOM_ICON"] // Here you change "nil" by the name of your image icon
animated:shouldAnimate];
[_markers addObject:marker];
[_renderedClusterItems addObject:item];
...
}
Second, I added this function in my Swift file of my map :
private func setupClusterManager() {
let iconGenerator = GMUDefaultClusterIconGenerator()
let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
let renderer = GMUDefaultClusterRenderer(mapView: maMap,
clusterIconGenerator: iconGenerator)
clusterManager = GMUClusterManager(map: maMap, algorithm: algorithm,
renderer: renderer)
}
Third, I added a variable in the POIItem class in order to get information from Firebase, to show it in infoWindows of markers:
class POIItem: NSObject, GMUClusterItem {
var position: CLLocationCoordinate2D
var name: String!
var snippet: String! // I add it here
init(position: CLLocationCoordinate2D, name: String, snippet: String) {
self.position = position
self.name = name
self.snippet = snippet // I add it also here
}
}
I get the informations of markers from Firebase thanks to POIItem class in the following function (before I call the function loadMarker() in order to load the data of each markers from Firebase):
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
if let poiItem = marker.userData as? POIItem {
NSLog("Did tap marker for cluster item \(poiItem.name!)")
marker.title = "\(poiItem.name!)"
marker.snippet = "\(poiItem.snippet!)"
self.estTouche = true
if self.estTouche == true {
self.alert(self.estTouche as AnyObject) // If true it shows an alertController
} else {
print("estTouche est false")
}
print(self.estTouche)
} else {
NSLog("Did tap a normal marker")
}
return false
}
Here's the whole code of the solution, it works fine for me.
import UIKit
import GoogleMaps
import CoreLocation
import Firebase
import FirebaseAuth
import FirebaseDatabase
/// Point of Interest Item which implements the GMUClusterItem protocol.
class POIItem: NSObject, GMUClusterItem {
var position: CLLocationCoordinate2D
var name: String!
var snippet: String!
init(position: CLLocationCoordinate2D, name: String, snippet: String) {
self.position = position
self.name = name
self.snippet = snippet
}
}
class NewCarteViewController: UIViewController, GMSMapViewDelegate, CLLocationManagerDelegate, GMUClusterManagerDelegate {
var locationManager = CLLocationManager()
var positionActuelle = CLLocation()
var positionEvent = CLLocationCoordinate2D()
var currentPosition = CLLocationCoordinate2D()
var latiti: CLLocationDegrees!
var longiti: CLLocationDegrees!
private var clusterManager: GMUClusterManager! // Cluster
private var maMap: GMSMapView!
var marker = GMSMarker()
var ref = DatabaseReference() // Firebase reference
var estTouche: Bool!
let geoCoder = CLGeocoder()
// For load the map
override func loadView() {
let camera = GMSCameraPosition.camera(withLatitude: 48.898902,
longitude: 2.282664, zoom: 12)
maMap = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
self.view = maMap
}
override func viewDidLoad() {
super.viewDidLoad()
let iconGenerator = GMUDefaultClusterIconGenerator()
let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm() // crée un gestionnaire de groupes utilisant l'algorithme
let renderer = GMUDefaultClusterRenderer(mapView: maMap, clusterIconGenerator: iconGenerator) // Le renderer est le moteur de rendu des groupes
clusterManager = GMUClusterManager(map: maMap, algorithm: algorithm, renderer: renderer)
loadMarker()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
positionActuelle = locationManager.location!
latiti = positionActuelle.coordinate.latitude
longiti = positionActuelle.coordinate.longitude
currentPosition = CLLocationCoordinate2D(latitude: latiti, longitude: longiti)
maMap.mapType = .normal
maMap.settings.compassButton = true // Boussole
maMap.isMyLocationEnabled = true // User current position icon
maMap.settings.myLocationButton = true // Button for center the camera on the user current position
maMap.delegate = self
}
// Download datas of markers from Firebase Database
func loadMarker() {
ref = Database.database().reference()
let usersRef = ref.child("markers")
usersRef.observeSingleEvent(of: .value, with: { (snapshot) in
if (snapshot.value is NSNull) {
print("not found")
} else {
for child in snapshot.children {
let userSnap = child as! DataSnapshot
let uid = userSnap.key // The uid of each user
let userDict = userSnap.value as! [String: AnyObject] // Child data
let latitudes = userDict["latitudeEvent"] as! Double
let longitudes = userDict["longitudeEvent"] as! Double
let bellname = userDict["nom"] as! String
let belltitre = userDict["titreEvent"] as! String
let total = snapshot.childrenCount // Count of markers save in my Firebase database
print("Total de marqueurs : \(total)")
let positionMarker = CLLocationCoordinate2DMake(bellatitude, bellongitude)
var diff = Double(round(100*self.getDistanceMetresBetweenLocationCoordinates(positionMarker, coord2: self.currentPosition))/100)
var dif = Double(round(100*diff)/100)
var positionEvenement = CLLocation(latitude: latitudes, longitude: longitudes)
// Function in order to convert GPS Coordinate in an address
CLGeocoder().reverseGeocodeLocation(positionEvenement, completionHandler: {(placemarks, error) -> Void in
if error != nil {
print("Reverse geocoder meets error " + (error?.localizedDescription)!)
return
}
if (placemarks?.count)! > 0 {
print("PlaceMarks \((placemarks?.count)!)")
let pm = placemarks?[0] as! CLPlacemark
var adres = "\(pm.name!), \(pm.postalCode!) \(pm.locality!)"
let item = POIItem(position: CLLocationCoordinate2DMake(latitudes, longitudes), name: "\(belltitre)", snippet: "Live de \(bellname)\nLieu: \(adres)\nDistance: \(dif) km") // This line is very important in order to import data from Firebase and show in infoWindow for the right datas for each markers
self.clusterManager.add(item)
self.clusterManager.cluster()
self.clusterManager.setDelegate(self, mapDelegate: self)
} else {
print("Problème avec les données reçues par le géocoder")
}
})
}
}
})
}
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
if let poiItem = marker.userData as? POIItem {
NSLog("Did tap marker for cluster item \(poiItem.name!)")
marker.title = "\(poiItem.name!)" // Title of the marker infoWindow (title from Firebase)
marker.snippet = "\(poiItem.snippet!)" // Same for snippet
self.estTouche = true
if self.estTouche == true {
self.alert(self.estTouche as AnyObject) // Show the alertController because infoWindows can't use button
} else {
print("estTouche est false")
}
print(self.estTouche)
} else {
NSLog("Did tap a normal marker")
}
return false
}
// If I tap a cluster icon, it zoom in +1
func clusterManager(_ clusterManager: GMUClusterManager, didTap cluster: GMUCluster) -> Bool {
let newCamera = GMSCameraPosition.camera(withTarget: cluster.position, zoom: maMap.camera.zoom + 1)
let update = GMSCameraUpdate.setCamera(newCamera)
maMap.moveCamera(update)
return false
}
private func setupClusterManager() {
let iconGenerator = GMUDefaultClusterIconGenerator()
let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
let renderer = GMUDefaultClusterRenderer(mapView: maMap,
clusterIconGenerator: iconGenerator)
clusterManager = GMUClusterManager(map: maMap, algorithm: algorithm,
renderer: renderer)
}
func renderer(_ renderer: GMUClusterRenderer, markerFor object: Any) -> GMSMarker? {
if let model = object as? POIItem {
self.clusterManager.cluster()
self.clusterManager.setDelegate(self, mapDelegate: self)
}
return nil
}
// Distance between 2 locations
func getDistanceMetresBetweenLocationCoordinates(_ coord1: CLLocationCoordinate2D, coord2: CLLocationCoordinate2D) -> Double {
let location1 = CLLocation(latitude: coord1.latitude, longitude: coord1.longitude)
let location2 = CLLocation(latitude: coord2.latitude, longitude: coord2.longitude)
var distance = ((location1.distance(from: location2)) / 1000)
return distance
}
// Show alertController with 2 buttons and a Cancel button
func alert(_ sender: AnyObject) {
let alertController = UIAlertController(title: "", message: "", preferredStyle: .actionSheet) // Ne me donne pas le bon nom
alertController.title = nil
alertController.message = nil // Supprime la ligne message sous le titre afin de pouvoir centrer le titre
alertController.addAction(UIAlertAction(title: "Accéder au live", style: .default, handler: self.accederLive))
alertController.addAction(UIAlertAction(title: "Infos event", style: .default, handler: self.infosEvent)) // Ou Affichage du profil utilisateur
alertController.addAction(UIAlertAction(title: "Annuler", style: .cancel, handler: nil))
self.present(alertController, animated: true, completion: nil)
}
// The two following functions are used in alertController
func accederLive(_ sender: AnyObject) {
...
}
func infosEvent(_ sender: AnyObject) {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Event")
present(vc, animated: true, completion: nil)
}
func mapView(_ mapView: GMSMapView!, markerInfoWindow marker: GMSMarker!) -> UIView! {
let infoWindow = Bundle.main.loadNibNamed("InfoWindow", owner: self, options: nil)?.first! as! CustomInfoWindow
return nil
}
}
Hope it can help someone else.
I add finally my way to load the data of the marker in Firebase in another Swift file (if it can help someone to do it too) :
var locationManage = CLLocationManager()
var positionActuel = CLLocation() // Current position of user
var latitudinale: CLLocationDegrees! // Latitude
var longitudinale: CLLocationDegrees! // Longitude
var m = GMSMarker()
class AddEventViewController: UIViewController, UISearchBarDelegate, GMSMapViewDelegate, CLLocationManagerDelegate {
var categorie: String! // Type of event
var titre: String! // Title of event
var name: String! // Username
var userId = Auth.auth().currentUser?.uid // Get the uid of the connected user in Firebase
#IBOutlet weak var titreTextField: UITextField! // TextField in where user can set a title
override func viewDidLoad() {
super.viewDidLoad()
...
locationManage.delegate = self
locationManage.requestWhenInUseAuthorization()
positionActuel = locationManage.location!
latitudinale = positionActuel.coordinate.latitude
longitudinale = positionActuel.coordinate.longitude
name = Auth.auth().currentUser?.displayName // In order to get the username of the connected user in Firebase
}
#IBAction func goAction(_ sender: Any) {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Live")
self.present(vc, animated: true, completion: nil)
if titreTextField.text == "" {
titre = "\(name!) Live \(categorie!)"
} else {
titre = titreTextField.text!
}
setMarker(marker: m) // Add a marker on the map
}
// Save data of this event in Firebase (and this marker on Firebase)
func setMarker(marker: GMSMarker) {
var lati = latitudinale
var longi = longitudinale
var nom = self.name
var title = self.titre
var userMarker = ["nom": nom!, // User name
"latitudeEvent": lati!, // Latitude of event
"longitudeEvent": longi!, // Longitude of event
"titreEvent": title!] as [String : AnyObject] // Title of event
KeychainWrapper.standard.set(userId!, forKey: "uid")
let emplacement = Database.database().reference().child("markers").child(userId!) // Reference of my Firebase Database
emplacement.setValue(userMarker)
}
}
I am working on Swift Google Maps. I cannot get the didTapMarker delegate to execute when the user taps on the marker. I put the mapView.delegate = self in the viewDidLoad method, but it did not help.
import UIKit
import GoogleMaps
import Alamofire
import ObjectMapper
import SwiftyJSON
class ViewController: UIViewController, GMSMapViewDelegate, GMUClusterManagerDelegate, CLLocationManagerDelegate {
var locationManager = CLLocationManager()
lazy var mapView = GMSMapView()
private var clusterManager: GMUClusterManager!
//true - marker clustering / false - map markers without clustering
let isClustering : Bool = false
//true - images / false - default icons
let isCustom : Bool = false
var userLocation: CLLocation = CLLocation(latitude: 0, longitude: 0)
override func viewDidLoad() {
super.viewDidLoad()
// User Location
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = 10
locationManager.startUpdatingLocation()
mapView.delegate = self
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
userLocation = locations.last!
print("userLocation latitude \(self.userLocation.coordinate.latitude)")
print("userLocation longitude \(self.userLocation.coordinate.longitude)")
let camera = GMSCameraPosition.camera(withLatitude: userLocation.coordinate.latitude,
longitude: userLocation.coordinate.longitude, zoom: 17.0)
mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
mapView.settings.myLocationButton = true
mapView.settings.scrollGestures = true
mapView.settings.zoomGestures = true
mapView.isMyLocationEnabled = true
self.view = mapView
locationManager.stopUpdatingLocation()
//locationManager.delegate = nil
fetch()
}
func fetch () {
let cityLocationService = CityLocationService()
let cityService = cityLocationService.getCityService(latitude: self.userLocation.coordinate.latitude , longitude: self.userLocation.coordinate.longitude)
cityService.fetch(latitude: self.userLocation.coordinate.latitude, longitude: self.userLocation.coordinate.longitude) { (incidents) in
let incidentsJson = incidents
DispatchQueue.main.async(execute: {
self.didGetJson(incidentsJson: incidentsJson)
})
}
}
func didGetJson(incidentsJson: JSON) {
if self.isClustering {
var iconGenerator : GMUDefaultClusterIconGenerator!
if self.isCustom {
var images : [UIImage] = []
for imageID in 1...5 {
images.append(UIImage(named: "m\(imageID).png")!)
}
iconGenerator = GMUDefaultClusterIconGenerator(buckets: [ 10, 50, 100, 200, 500 ], backgroundImages: images)
} else {
iconGenerator = GMUDefaultClusterIconGenerator()
}
let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
let renderer = GMUDefaultClusterRenderer(mapView: self.mapView, clusterIconGenerator: iconGenerator)
self.clusterManager = GMUClusterManager(map: self.mapView, algorithm: algorithm, renderer: renderer)
self.addToMap(resultJson: incidentsJson, isCluster: true)
// Call cluster() after items have been added to perform the clustering and rendering on map.
self.clusterManager.cluster()
// Register self to listen to both GMUClusterManagerDelegate and GMSMapViewDelegate events.
self.clusterManager.setDelegate(self, mapDelegate: self)
} else {
self.addToMap(resultJson: incidentsJson, isCluster: false)
}
self.view = self.mapView
}
func addToMap(resultJson: JSON, isCluster: Bool) {
for(_, subJson): (String, JSON) in resultJson {
let position = self.checkIfMutlipleCoordinates(latitude: subJson["latitude"].floatValue, longitude: subJson["longitude"].floatValue)
let id = subJson["id"]
let type = subJson["type"].stringValue
let address = subJson["address"].stringValue
// let case_number = subJson["case_number"].stringValue
let date = subJson["date"].stringValue
let markerImage = subJson["markerImage"].stringValue
if isCluster {
let item = POIItem(position: position, name: "#\(id)")
// print("pdid name=\(item.name),latitude=\(item.position.latitude),longitude=\(item.position.longitude).")
clusterManager.add(item)
} else {
let marker = GMSMarker(position: position)
marker.title = "#\(id)"
let image = UIImage(named: markerImage)
marker.icon = image?.resized(to: CGSize(width: 30, height: 30))
marker.opacity = 0.6
marker.snippet = "\r\n date: \(date) id # \(id) \r\n address: \(address) \r\n type: \(type)"
marker.map = mapView
}
}
}
func checkIfMutlipleCoordinates(latitude : Float , longitude : Float) -> CLLocationCoordinate2D{
var lat = latitude
var lng = longitude
let variation = (self.randomFloat(min: 0.0, max: 2.0) - 0.5) / 1500
lat = lat + variation
lng = lng + variation
let finalPos = CLLocationCoordinate2D(latitude: CLLocationDegrees(lat), longitude: CLLocationDegrees(lng))
return finalPos
}
func randomFloat(min: Float, max:Float) -> Float {
return (Float(arc4random()) / 0xFFFFFFFF) * (max - min) + min
}
func clusterManager(clusterManager: GMUClusterManager, didTapCluster cluster: GMUCluster) {
let newCamera = GMSCameraPosition.camera(withTarget: cluster.position,
zoom: mapView.camera.zoom + 1)
let update = GMSCameraUpdate.setCamera(newCamera)
mapView.moveCamera(update)
}
//Show the marker title while tapping
func mapView(mapView: GMSMapView, didTapMarker marker: GMSMarker) -> Bool {
print("tapped on marker")
if marker.title == "myMarker"{
print("handle specific marker")
}
return true
}
//Optional Feature:
//Add new markers while tapping at coordinates without markers/clusters
func mapView(mapView: GMSMapView, didTapAtCoordinate coordinate: CLLocationCoordinate2D) {
let item = POIItem(position: coordinate, name: "NEW")
clusterManager.add(item)
clusterManager.cluster()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Add delegate GMSMapViewDelegate
mapView.delegate = self // in viewDidLoad
If you want to print lat and long of the touched marker, this is the code:
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
print("You tapped : \(marker.position.latitude),\(marker.position.longitude)")
return true // or false as needed.
}
And for long press, if you want to redirect to google maps.
func mapView(_ mapView: GMSMapView, didLongPressInfoWindowOf marker: GMSMarker) {
if (UIApplication.shared.canOpenURL(NSURL(string:"comgooglemaps://")! as URL)) {
UIApplication.shared.open(NSURL(string:"comgooglemaps://?saddr=&daddr=\(marker.position.latitude),\(marker.position.longitude)&directionsmode=driving")! as URL, options: [:], completionHandler: nil)
}
else {
let alert = UIAlertController(title: "Google Maps not found", message: "Please install Google Maps in your device.", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
This will work!!!
I'm designing an app which has the a feature to let user add their own pin. Recently, I found my app has a memory leak with the title of "ContiguousArrayStorage". I debugged a little and figured out it was a problem with my for loop in my viewdidload, but I am not sure how to fix the leak.
Here is my code:
#IBOutlet weak var AppleMap: MKMapView!
#IBOutlet weak var LogoutOutlet: UIButton!
#IBOutlet weak var OutletforAddPokemon: UIButton!
#IBOutlet weak var FindLocationOutlet: UIButton!
#IBOutlet weak var FilterOutlet: UIButton!
let locationManager = CLLocationManager()
let calendar: NSCalendar! = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
var increment:Int = 0
var currentLoc:CLLocationCoordinate2D?
var centerMap = true
let StoringPin = FIRDatabase.database().reference().child("locations")
var Date = NSDate()
override func viewDidLoad() {
super.viewDidLoad()
AppleMap.delegate = self
StoringPin.observeEventType(.Value, withBlock: {
snapshot in
if snapshot.value is NSNull {
return
}
let val = snapshot.value as! [String : [String : AnyObject]]
for key in val.keys {
let latitudedata = val[key]!["latitude"] as! Double
let longitudedata = val[key]!["longitude"] as! Double
let namedata = val[key]!["name"] as! String
let Username = val[key]!["Username"]
as! String
let DATE = val[key]!["Date"]
as! String
let NumberOflikesforuser = val[key]!["Likes"] as! Int
let NumberOfDislikesforuser = val[key]!["Dislikes"] as! Int
let coord = CLLocationCoordinate2D(latitude: latitudedata, longitude: longitudedata)
let artwork = Capital(title: "\(namedata)", coordinate: coord, info: "HI", username: Username, NumofLikes: NumberOflikesforuser,NumofDisLikes: NumberOfDislikesforuser, UIDSTring: UID, date: DATE, color: MKPinAnnotationColor.Green)
artwork.subtitle = DATE
print("k")
let permastringforemail:String = Username
print(++self.increment)
print(UID)
print(permastringforemail)
stringforemail = permastringforemail
Arrayforpins.append(artwork)
self.AppleMap.addAnnotation(Arrayforpins[Arrayforpins.count - 1])
for Capital in Arrayforpins {
self.AppleMap.addAnnotation(Capital)
}
}
})
print(LogoutOutlet)
LogoutOutlet.layer.cornerRadius = 4
FindLocationOutlet.layer.cornerRadius = 4
OutletforAddPokemon.layer.cornerRadius = 4
//FilterOutlet.layer.cornerRadius = 4
self.locationManager.requestAlwaysAuthorization()
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
let annotationView = MKAnnotationView()
let detailButton: UIButton = UIButton.init(type: .DetailDisclosure) as UIButton
annotationView.rightCalloutAccessoryView = detailButton
}
let regionRadius: CLLocationDistance = 1000
func centerMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
regionRadius * 2.0, regionRadius * 2.0)
AppleMap.setRegion(coordinateRegion, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue:CLLocationCoordinate2D = manager.location!.coordinate
if CLLocationManager.authorizationStatus() == .AuthorizedWhenInUse {
AppleMap.showsUserLocation = true
} else {
locationManager.requestWhenInUseAuthorization()
}
print("update")
currentLoc = locValue
if centerMap {
centerMap = false
centerMapOnLocation(CLLocation(latitude: currentLoc!.latitude, longitude: currentLoc!.longitude))
}
}
#IBAction func SendtoSelector(sender: AnyObject) {
self.performSegueWithIdentifier("SeguetoSelector", sender: self)
}
#IBAction func FilterFunc(sender: AnyObject) {
self.performSegueWithIdentifier("SeguetoFilter", sender: self)
}
#IBAction func FindLocation(sender: AnyObject) {
centerMapOnLocation(CLLocation(latitude: currentLoc!.latitude, longitude: currentLoc!.longitude))
}
#IBAction func Logout(sender: AnyObject) {
LO = true
self.performSegueWithIdentifier("BacktoLoginScreen", sender: self)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
locationManager
if IndexBoolean == true{
//let annotationView = MKPinAnnotationView()
print("Hi")
let artwork = Capital(title: "\(pickerDataSource[chosenindex])", coordinate: CLLocationCoordinate2D(latitude: currentLoc!.latitude, longitude: currentLoc!.longitude), info: "HEY", username: stringforemail, NumofLikes: NumberOfLikes, NumofDisLikes: NumberOfDislike, UIDSTring: UID, date: stringfordate2, color: MKPinAnnotationColor.Green)
//print(now)
print(chosenindex)
artwork.title = "\(pickerDataSource[chosenindex])"
//artwork.subtitle = stringfordate
AppleMap.addAnnotation(artwork)
//annotationView.pinColor = artwork.Green
Arrayforpins.append(artwork)
print(stringforemail)
AppleMap.addAnnotation(Arrayforpins[Arrayforpins.count - 1])
for Capital in Arrayforpins{
AppleMap.addAnnotation(Capital)
}
IndexBoolean = false
var formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
formatter.timeZone = NSTimeZone(abbreviation: "Central Time")
var utcTimeZoneSTR = formatter.stringFromDate(Date)
stringfordate = "\(utcTimeZoneSTR)"
let uid = NSUUID().UUIDString
UID = uid
StoringPin.child(uid).setValue(["name" : pickerDataSource[chosenindex],
"latitude" : currentLoc!.latitude,
"longitude" : currentLoc!.longitude,"Array Position" : chosenindex,"Username": stringforemail, "Likes": NumberOfLikes2, "Dislikes":
NumberOfDislike, "UID": UID, "Date": stringfordate])
if FilterBoolean == true {
print("b")
if FilterDataSource[Intforfilter] != stringforname {
print("k")
//self.AppleMap.viewForAnnotation(artwork)?.hidden = true
FilterBoolean == false
}
//else {
// print("m")
// self.AppleMap.removeAnnotation(artwork)
//
// }
FilterBoolean == false
}
}
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "Capital"
print(++increment)
if annotation.isKindOfClass(Capital.self) {
print("CAPITAL")
if let annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier) {
annotationView.annotation = annotation
return annotationView
} else {
let annotationView = MKPinAnnotationView(annotation:annotation, reuseIdentifier:identifier)
annotationView.enabled = true
annotationView.canShowCallout = true
//annotationView.pinColor = MKPinAnnotationColor.Green
let btn = UIButton(type: .DetailDisclosure)
annotationView.rightCalloutAccessoryView = btn
return annotationView
}
}
return nil
}
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
let capital = view.annotation as! Capital
let placeName = capital.title
let placeInfo = capital.info
let UserName = capital.username
stringforname = view.annotation!.title!!
coords = view.annotation!.coordinate
stringforemail = capital.username
stringfordate2 = capital.date
NumberOfLikes2 = capital.NumofLikes
UID = capital.UIDSTring
print(stringforname)
print(UID)
self.performSegueWithIdentifier("SegueToInfo", sender: self)
}
I note you're not taking care to specify how to capture self in your closure. When in a disposable object context (a UIViewController) and an async closure you always have to worry about this. You need to capture it as weak or unowned. Are you familiar with closure capture lists?
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID56
The pattern I use is to capture self weakly and then bail if self has become nil, e.g. the UIViewController has been dismissed and harvested. If it is still around, I temporarily capture it strongly with a local variable in a guard...let statement.
withBlock: { [weak self] (snapshot) in
guard let s = self else {
print("Callback called after view unloaded")
return
}
// now use 's' instead of 'self'
...
}
Can't say this is the only problem because we don't have the declarations for your helper classes. For example we don't know what mischief Capital is up to.
By the way, just be clear that your for loop does not run at viewDidLoad(). You're merely registering a callback that only reacts if and when the .Value event occurs on the StoringPin object.
I've just got stuck trying to add a detail button to my annotation point, unfortunately I don't know how to do it. Does anyone could help me with that?
The image below presents what I'd like to achieve. Thanks!
MapKitViewController:
import UIKit
import MapKit
import CoreLocation
class MapKitViewController: UIViewController, MKMapViewDelegate
{
let locationManager = CLLocationManager()
#IBOutlet weak var nmapView: MKMapView!
override func viewDidLoad()
{
super.viewDidLoad()
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
let location = CLLocationCoordinate2D(
latitude: 53.4265107,
longitude: 14.5520357)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegion(center: location, span: span)
nmapView.setRegion(region, animated: true)
nmapView.showsPointsOfInterest = false
nmapView.showsUserLocation = true
displayMarkers()
}
func displayMarkers() -> Void
{
let jsonURL: NSURL = NSURL(string: "http://jsonstring.com/")!
var dataFromNetwork: NSData = NSData(contentsOfURL: jsonURL)!
let json = JSON(data: dataFromNetwork)
var jsonSize = json.count
var todaysDate:NSDate = NSDate()
var dateFormatter:NSDateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
var formattedDate:String = dateFormatter.stringFromDate(todaysDate)
let annotationView = MKAnnotationView()
let detailButton: UIButton = UIButton.buttonWithType(UIButtonType.DetailDisclosure) as UIButton
annotationView.rightCalloutAccessoryView = detailButton
for(var i = 0; i < jsonSize; i++)
{
if(json[i]["rozpoczecie"].stringValue == formattedDate)
{
let clubID = json[i]["id_klub"].stringValue
let annotation = MKPointAnnotation()
let (resultSet, err) = SD.executeQuery("SELECT * FROM Clubs WHERE ID = ?", withArgs: [clubID])
if(err != nil){println("blad")}
else
{
for row in resultSet
{
let name = row["Name"]?.asString()
let latitude = row["Latitude"]?.asDouble()
let longitude = row["Longitude"]?.asDouble()
annotation.title = name
var markerLatitude: Double = latitude!
var markerLongitude: Double = longitude!
let location = CLLocationCoordinate2D(latitude: markerLatitude, longitude: markerLongitude)
annotation.setCoordinate(location)
annotation.subtitle = json[i]["nazwa"].stringValue
}
nmapView.addAnnotation(annotation)
}
}
}
}
You are doing it right.You just need to have these methods implemented for adding button along with title and subtitle
iOS 8 and Xcode 6
import UIKit
import MapKit
import CoreLocation
class MapKitViewController: UIViewController, MKMapViewDelegate
{
let locationManager = CLLocationManager()
#IBOutlet weak var nmapView: MKMapView!
override func viewDidLoad()
{
super.viewDidLoad()
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
let location = CLLocationCoordinate2D(
latitude: 53.4265107,
longitude: 14.5520357)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegion(center: location, span: span)
nmapView.setRegion(region, animated: true)
nmapView.showsPointsOfInterest = false
nmapView.showsUserLocation = true
displayMarkers()
}
// When user taps on the disclosure button you can perform a segue to navigate to another view controller
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!) {
if control == view.rightCalloutAccessoryView{
println(view.annotation.title) // annotation's title
println(view.annotation.subtitle) // annotation's subttitle
//Perform a segue here to navigate to another viewcontroller
// On tapping the disclosure button you will get here
}
}
// Here we add disclosure button inside annotation window
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
println("viewForannotation")
if annotation is MKUserLocation {
//return nil
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if pinView == nil {
//println("Pinview was nil")
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
}
var button = UIButton.buttonWithType(UIButtonType.DetailDisclosure) as UIButton // button with info sign in it
pinView?.rightCalloutAccessoryView = button
return pinView
}
func displayMarkers() -> Void
{
let jsonURL: NSURL = NSURL(string: "http://atnight.wtznc.com/json.php")!
var dataFromNetwork: NSData = NSData(contentsOfURL: jsonURL)!
let json = JSON(data: dataFromNetwork)
var jsonSize = json.count
var todaysDate:NSDate = NSDate()
var dateFormatter:NSDateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
var formattedDate:String = dateFormatter.stringFromDate(todaysDate)
let annotationView = MKAnnotationView()
// Adding button here wont do anything so remove these two lines
let detailButton: UIButton = UIButton.buttonWithType(UIButtonType.DetailDisclosure) as UIButton
annotationView.rightCalloutAccessoryView = detailButton
// For adding button we have to use a method named as viewForAnnotation
for(var i = 0; i < jsonSize; i++)
{
if(json[i]["rozpoczecie"].stringValue == formattedDate)
{
let clubID = json[i]["id_klub"].stringValue
let annotation = MKPointAnnotation()
let (resultSet, err) = SD.executeQuery("SELECT * FROM Clubs WHERE ID = ?", withArgs: [clubID])
if(err != nil){println("blad")}
else
{
for row in resultSet
{
let name = row["Name"]?.asString()
let latitude = row["Latitude"]?.asDouble()
let longitude = row["Longitude"]?.asDouble()
annotation.title = name
var markerLatitude: Double = latitude!
var markerLongitude: Double = longitude!
let location = CLLocationCoordinate2D(latitude: markerLatitude, longitude: markerLongitude)
annotation.setCoordinate(location)
annotation.subtitle = json[i]["nazwa"].stringValue
}
nmapView.addAnnotation(annotation)
}
}
}
}
}
Check out my output.