I want to update map view every 60 seconds & make an annotation with custom pin/image but want to show standard pin [red color - See Figure 6-1] icon to the previously drawn annotation. I tried like below code but that does not working properly. With another custom image it works but i can't show that default/standard red pin to previous annotation. Please see "currentLocationHasBeenUpdated" function where i tried to show standard red icon to the previous annotation. Please let me know how can i achieve this. Thanks.
My ViewController :
import UIKit
import MapKit
class FirstTabController: UIViewController, MKMapViewDelegate, DelegateForUpdateCurrentLocation {
#IBOutlet weak var mapView: MKMapView!
var gpsLocations : [[String: AnyObject]]!
var dataManager : DataManager!
var currentAnnotation : MKAnnotation!
//Return CLLocation Coordinate
func getLocationObject(latitude:Double, longitude:Double) -> CLLocationCoordinate2D {
return CLLocationCoordinate2D(
latitude: latitude,
longitude: longitude
)
}
//Create annotation object & return
func createAnnotation(latitude:Double, longitude:Double, locationName:String, territory:String) -> MKPointAnnotation {
let annotation = MKPointAnnotation()
annotation.coordinate = self.getLocationObject(latitude, longitude: longitude)
annotation.title = locationName
annotation.subtitle = territory
return annotation
}
//Create annotaion for current ship position
func createAnnotationForCurrentPosition(location:[String: AnyObject]) -> MKPointAnnotation {
let latitude = (location["latitude"] as? Double)!
let longitude = (location["longitude"] as? Double)!
let name = (location["locationName"] as? String)!
let territory = (location["territory"] as? String)!
return self.createAnnotation(latitude, longitude: longitude, locationName: name, territory: territory)
}
//Set region on map view
func setRegion(location:[String: AnyObject]){
let latitude = (location["latitude"] as? Double)!
let longitude = (location["longitude"] as? Double)!
let location = self.getLocationObject(latitude, longitude: longitude)
//Set zoom span
let span = MKCoordinateSpanMake(0.05, 0.05)
//Create region on map view & show
let region = MKCoordinateRegion(center: location, span: span)
self.mapView.setRegion(region, animated: true)
}
//This function will fire from data manager when current location from API has been updated
func currentLocationHasBeenUpdated(location:[String: AnyObject]){
dispatch_async(dispatch_get_main_queue()){
if self.currentAnnotation != nil {
var currentAnnotationView = self.mapView.viewForAnnotation(self.currentAnnotation)
if currentAnnotationView != nil {
currentAnnotationView.image = nil //this line makes app crash [gave nil to show standard red icon]
// currentAnnotationView.image = UIImage(named:"first") - this line works perfectly with different icon. but i don't want any custom icon except the standard red one
}
}
self.mapView.addAnnotation(self.createAnnotationForCurrentPosition(location))
self.setRegion(location)
}
}
//Update map view by scheduling time if current location is changed yet
func updateMapView() {
self.dataManager.getCurrentLocation()
}
override func viewDidLoad() {
super.viewDidLoad()
//Get gps locations from data manager
self.dataManager = DataManager()
self.dataManager.delegate2 = self
self.dataManager.getCurrentLocation()
//self.mapView.userTrackingMode = MKUserTrackingMode.FollowWithHeading
//Get GPS location by scheduling time
NSTimer.scheduledTimerWithTimeInterval(60, target: self, selector: Selector("updateMapView"), userInfo: nil, repeats: true)
}
func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer!{
if overlay is MKPolyline {
var polylineRenderer = MKPolylineRenderer(overlay: overlay)
polylineRenderer.strokeColor = UIColor.blueColor()
polylineRenderer.lineWidth = 2
return polylineRenderer
}
return nil
}
//Make custom annotaion pin if the annotation is of ship's current position
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView!{
println("Hello")
self.currentAnnotation = annotation
//Custom annotation view with custom pin icon
let reuseId = "custom"
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
annotationView.canShowCallout = true
}
else {
annotationView.annotation = annotation
}
//Set annotation specific properties after the view is dequeued or created...
annotationView.image = UIImage(named:"pinicon")
return annotationView
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
and for coordinates from api
import Foundation
extension String {
func toDouble() -> Double? {
return NSNumberFormatter().numberFromString(self)?.doubleValue
}
}
class DataSet{
var settings : Settings!
var getService : GetService!
var currentLocation : [String: AnyObject]!
//Object initialization for API call
init(){
self.settings = Settings()
self.getService = GetService()
}
func getCurrentLocation(callback:([String: AnyObject]) -> ()){
self.getService.apiCallToGet(self.settings.getCoordinates(), callback: {
(response) in
var location = [String: AnyObject]()
for item in response {
if let dictionary = item as? NSDictionary {
if let lat = dictionary["Lat"] as? String {
if lat.toDouble() != nil {
location["latitude"] = lat.toDouble()!
}
}
if let long = dictionary["Long"] as? String {
if long.toDouble() != nil {
location["longitude"] = long.toDouble()!
}
}
if let name = dictionary["Name"] as? String {
location["locationName"] = name
}
if let territory = dictionary["Territory"] as? String {
location["territory"] = territory
}
println(location["latitude"]!)
println(location["longitude"]!)
if self.currentLocation != nil {
if ((self.currentLocation["latitude"] as? Double) != (location["latitude"] as? Double)) && ((self.currentLocation["longitude"] as? Double) != (location["longitude"] as? Double)){
self.currentLocation = location
callback(location)
}
} else {
self.currentLocation = location
callback(location)
}
}
}
})
}
}
I have solved my problem by creating custom annotation class like below -
import UIKit
import MapKit
var ARROW_ANNOTATION : NSString = "ARROW_ANNOTATION"
var PIN_ANNOTATION : NSString = "PIN_ANNOTATION"
class Annotation: NSObject, MKAnnotation {
var currentLocation: CLLocationCoordinate2D
var _title : String
var subTitle : String
var direction : CLLocationDirection!
var typeOfAnnotation : String!
init(coordinate: CLLocationCoordinate2D, title : String, subTitle : String) {
self.currentLocation = coordinate
self._title = title
self.subTitle = subTitle
}
func getLocation() -> CLLocation {
return CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
}
var coordinate: CLLocationCoordinate2D {
return self.currentLocation
}
var title : String {
return self._title
}
var subtitle : String {
return self.subTitle
}
}
and In my ViewController file -
override func viewDidLoad() {
super.viewDidLoad()
var annotation1 : Annotation = Annotation(coordinate: location, title: name, subTitle: territory)
annotation.typeOfAnnotation = PIN_ANNOTATION as String
self.mapView.addAnnotation(annotation1)
var annotation2 : Annotation = Annotation(coordinate: location, title: name, subTitle: territory)
annotation.typeOfAnnotation = ARROW_ANNOTATION as String
self.mapView.addAnnotation(annotation2)
}
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView!{
let reuseId = "custom"
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
var customAnnotationView : MKAnnotationView!
if let _annotation = annotation as? Annotation {
if _annotation.typeOfAnnotation == PIN_ANNOTATION {
customAnnotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
customAnnotationView.canShowCallout = true
//customAnnotationView.draggable = true
} else {
customAnnotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
// 17 - Determine the direction
let arrowImage = UIImage(named:"arrow")!
let direction = _annotation.direction
customAnnotationView.image = self.rotatedImage(arrowImage, byDegreesFromNorth: direction)
customAnnotationView.canShowCallout = true
}
} else {
return nil
}
return customAnnotationView
}
Related
I am coming to a problem where I try to generate different icons to show on the map view of places. But, I need some help from you guys. So far, I have hard-coded a pin to show on the map view. I also, have different pins in my assets, I want to show them by generating it on the mapview. How can I generate different icons to show on my map view from the API? Thanks for the help.
Here is my code:
import UIKit
import MapKit
import CoreLocation
class MapViewController: BaseViewController{
#IBOutlet weak var leadingConstraints: NSLayoutConstraint!
#IBOutlet weak var menuView: UIView!
#IBOutlet weak var mapView: MKMapView!
fileprivate let locationManager = CLLocationManager()
fileprivate var startedLoadingPOIs = false
fileprivate var places = [Place]()
fileprivate var arViewController: ARViewController!
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
var nearMeIndexSelected = NearMeIndexTitle()
var menuShowing = false
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
locationManager.requestWhenInUseAuthorization()
//making shadow of our menu view
menuView.layer.shadowOpacity = 1
menuView.layer.shadowRadius = 7
}
#IBAction func showARController(_ sender: Any) {
arViewController = ARViewController()
arViewController.dataSource = self
arViewController.maxVisibleAnnotations = 30
arViewController.headingSmoothingFactor = 0.05
arViewController.setAnnotations(places)
self.navigationController!.pushViewController(arViewController, animated: true)
}
}
extension MapViewController: CLLocationManagerDelegate, MKMapViewDelegate {
// // Changing the Pin Color on the map.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
mapView.tintColor = #colorLiteral(red: 0.8823529412, green: 0.1647058824, blue: 0.1333333333, alpha: 1)
return nil
} else {
let annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "pin")
let pin = mapView.view(for: annotation) ?? MKAnnotationView(annotation: annotation, reuseIdentifier: nil)
pin.image = UIImage(named: "pins")
return pin
return annotationView
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if locations.count > 0 {
let location = locations.last!
print("Accuracy: \(location.horizontalAccuracy)")
if location.horizontalAccuracy < 100 {
manager.stopUpdatingLocation()
let span = MKCoordinateSpan(latitudeDelta: 0.013, longitudeDelta: 0.013)
let region = MKCoordinateRegion(center: location.coordinate, span: span)
mapView.region = region
if !startedLoadingPOIs {
DispatchQueue.main.async {
self.activityIndicator.startAnimating()
}
startedLoadingPOIs = true
let loader = PlacesLoader()
loader.loadPOIS(location: location, radius: 1500) { placesDict, error in
if let dict = placesDict {
guard let placesArray = dict.object(forKey: "results") as? [NSDictionary] else { return }
for placeDict in placesArray {
let latitude = placeDict.value(forKeyPath: "geometry.location.lat") as! CLLocationDegrees
let longitude = placeDict.value(forKeyPath: "geometry.location.lng") as! CLLocationDegrees
let reference = placeDict.object(forKey: "reference") as! String
let name = placeDict.object(forKey: "name") as! String
let address = placeDict.object(forKey: "vicinity") as! String
let location = CLLocation(latitude: latitude, longitude: longitude)
let place = Place(location: location, reference: reference, name: name, address: address)
self.places.append(place)
let annotation = PlaceAnnotation(location: place.location!.coordinate, title: place.placeName)
DispatchQueue.main.async {
self.mapView.addAnnotation(annotation)
}
}
DispatchQueue.main.async {
self.activityIndicator.stopAnimating()
self.mapView.isHidden = false
}
}
}
}
}
}
}
}
You can compare the coordinate of the annotation and specify custom pin for that Annotation.
if annotation.coordinate == "Your Custom Pin Coordinate" { //set custom pin }
Suppose I want to add a custom pin for my selected Place.
var selectedPlace: PlaceAnnotation
Inside your loop. suppose my selected place is "toronto"
if name == "toronto" { self.selectedPlace = annotation }
Then in ViewForAnnotation method
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation.coordinate = selectedPlace.coordinate {
pin.image = UIImage(named: "YOUR SELECTED IMAGE")
}
}
See here my demo to create a custom pin view customPinAnnotationButton
Here is the method to draw annotation with image , I subclassed MKAnoationView
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
{
if annotation is MyAnnotation == false
{
return nil
}
let senderAnnotation = annotation as! MyAnnotation
let pinReusableIdentifier = senderAnnotation.pinColor.rawValue
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: pinReusableIdentifier)
if annotationView == nil
{
annotationView = MKAnnotationView(annotation: senderAnnotation, reuseIdentifier: pinReusableIdentifier)
annotationView!.canShowCallout = false
}
if senderAnnotation.pinColor == PinColor.Green
{
let pinImage = UIImage(named:"directMarker3.png")
annotationView!.image = pinImage
}
return annotationView
}
here to add an annotation
let blueLocation = CLLocationCoordinate2D(latitude:30.45454554, longitude: 29.646727)
let blueAnnotation = MyAnnotation(coordinate: blueLocation, title:"ghghhg",subtitle: "hgnhhghghg",pinColor: .Green ,uid:"hghg",type:"provider")
self.mymap.addAnnotation(blueAnnotation)
self.mymap.showAnnotations(self.mymap.annotations, animated: true)
1.Define subclass of MKPointAnnotation:
class MyPointAnnotation: MKPointAnnotation {
var imageName: String = ""
}
2.Set image name.
let annotation = MyPointAnnotation()
annotation.coordinate = coordinate
annotation.title = "title"
annotation.subtitle = "subtitle"
annotation.imageName = "pin" // Set image name here
self.mapView.addAnnotation(annotation)
3.Load image in viewFor delegate method
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let reuseId = "image"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
if pinView == nil {
pinView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView?.canShowCallout = true
let annotation = annotation as! MyPointAnnotation
pinView?.image = UIImage(named: annotation.imageName)
let rightButton: AnyObject! = UIButton(type: UIButtonType.detailDisclosure)
pinView?.rightCalloutAccessoryView = rightButton as? UIView
}
else {
pinView?.annotation = annotation
}
return pinView
}
I've been having trouble figuring out how to pass a custom variable in a map pin to another view controller in Swift. I know that passing the coordinates, title, and subtitle are available when you addAnnotation. I would like to try and pass a custom variable but hidden. Is there such a thing? Below I am getting the users location, mapping it, dropping a pin of a couple locations nearby with annotations which goes to another view controller and passes just the title and subtitle. Any insight is greatly appreciated.
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
var mappedCity = String()
var mappedState = String()
var manager = CLLocationManager()
var annotation:MKAnnotation!
var error:NSError!
var pointAnnotation:MKPointAnnotation!
var pinAnnotationView:MKPinAnnotationView!
var selectedAnnotation: MKPointAnnotation!
private var mapChangedFromUserInteraction = false
#IBOutlet var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
self.mapView.delegate = self
self.navigationItem.titleView = searchController.searchBar
self.definesPresentationContext = true
if CLLocationManager.locationServicesEnabled(){
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation:CLLocation = locations[0]
let latitude = userLocation.coordinate.latitude
let longitude = userLocation.coordinate.longitude
let latDelta:CLLocationDegrees = 0.05
let lonDelta:CLLocationDegrees = 0.05
let span:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, lonDelta)
let location:CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
let region:MKCoordinateRegion = MKCoordinateRegionMake(location, span)
self.mapView.setRegion(region, animated: true)
self.mapView.showsUserLocation = true
CLGeocoder().reverseGeocodeLocation(userLocation) { (placemarks, error) in
if (error != nil){
print(error)
}else {
if let p = placemarks?[0]{
let locality = p.locality ?? ""
let administrativeArea = p.administrativeArea ?? ""
self.mappedCity = String(locality)
self.mappedState = String(administrativeArea)
self.parseJSON("\(locality)", state: "\(administrativeArea)")
}
}
}
self.manager.stopUpdatingLocation()
}
func parseJSON(city: String, state: String){
let passedCity = city
let passedState = state
let escapedCity = passedCity.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
let escapedState = passedState.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
let url = NSURL(string:"http://www.API.com/api.php?city=\(escapedCity)&stateAbv=\(escapedState)")!
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) { (items, response, error) -> Void in
if error != nil {
print(error)
}else {
if let items = items {
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(items, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
if jsonResult.count > 0 {
if let datas = jsonResult["data"] as? NSArray{
for data in datas{
if let title = data["title"] as? String {
if let street = data["street"] as? String {
if let city = data["city"] as? String {
if let stateAbv = data["stateAbv"] as? String {
if let zip = data["zip"] as? String {
self.geoAddress("\(title)", street: "\(street)", city: "\(city)", state: "\(stateAbv)", zip: "\(zip)")
}
}
}
}
}
}
}
}
} catch{}
}
}
}
task.resume()
}
func geoAddress(title: String, street: String, city: String, state: String, zip: String){
let storeName = "\(title)"
let location = "\(street) \(city) \(state) \(zip)"
let geocoder = CLGeocoder();
geocoder.geocodeAddressString(location, completionHandler: {(placemarks: [CLPlacemark]?, error: NSError?) -> Void in
if (error != nil) {
print("Error \(error!)")
} else if let placemark = placemarks?[0] {
let coordinates:CLLocationCoordinate2D = placemark.location!.coordinate
let pointAnnotation:MKPointAnnotation = MKPointAnnotation()
pointAnnotation.coordinate = coordinates
pointAnnotation.title = storeName
pointAnnotation.subtitle = location
self.mapView.addAnnotation(pointAnnotation)
}
})
}
private func mapViewRegionDidChangeFromUserInteraction() -> Bool {
let view: UIView = self.mapView.subviews[0] as UIView
// Look through gesture recognizers to determine whether this region change is from user interaction
if let gestureRecognizers = view.gestureRecognizers {
for recognizer in gestureRecognizers {
if( recognizer.state == UIGestureRecognizerState.Began || recognizer.state == UIGestureRecognizerState.Ended ) {
return true
}
}
}
return false
}
func mapView(mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
mapChangedFromUserInteraction = mapViewRegionDidChangeFromUserInteraction()
if (mapChangedFromUserInteraction) {
// user changed map region
}
}
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
if (mapChangedFromUserInteraction) {
// user changed map region
let center = mapView.centerCoordinate
let mapLatitude = center.latitude
let mapLongitude = center.longitude
let locationmove = CLLocation(latitude: mapLatitude, longitude: mapLongitude)
CLGeocoder().reverseGeocodeLocation(locationmove) { (placemarks, error) in
if (error != nil){
print(error)
}else {
if let p = placemarks?[0]{
let locality = p.locality ?? ""
let administrativeArea = p.administrativeArea ?? ""
self.mappedCity = String(locality)
self.mappedState = String(administrativeArea)
self.parseJSON("\(locality)", state: "\(administrativeArea)")
}
}
}
}
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
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?.animatesDrop = false
pinView?.canShowCallout = true
pinView?.draggable = true
pinView?.pinTintColor = UIColor.greenColor()
let rightButton: AnyObject! = UIButton(type: UIButtonType.DetailDisclosure)
pinView?.rightCalloutAccessoryView = rightButton as? UIView
}
else {
pinView?.annotation = annotation
}
return pinView
}
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView {
selectedAnnotation = view.annotation as? MKPointAnnotation
performSegueWithIdentifier("Details", sender: self)
}
}
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, didChangeDragState newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
if newState == MKAnnotationViewDragState.Ending {
let droppedAt = view.annotation?.coordinate
print(droppedAt)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "Details"){
let myDetails = segue.destinationViewController as! DetailViewController
myDetails.mytitle = selectedAnnotation.title
myDetails.mysubtitle = selectedAnnotation.subtitle
}
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
}
}
Subclass the "MKPointAnnotation" class and add your custom property in it.
class MyAnnotation : MKPointAnnotation {
var customProperty : String?
}
And you can use MyAnnotation instead of MKPointAnnotation. Like following
let pointAnnotation:MyAnnotation = MyAnnotation()
pointAnnotation.coordinate = coordinates
pointAnnotation.title = storeName
pointAnnotation.subtitle = location
pointAnnotation.customProperty = "your value"
self.mapView.addAnnotation(pointAnnotation)
I'm trying to build an app for iOS 8 using Swift which uses a Parse.com database to display pins on a MapView. I've succeeded in loading all the pins on the map us PFGeoPoints, but I'm trying to add a disclosure button to each pin which will perform a segue to show extra info.
I've double checked my code but I'm missing something, does anyone notice problems?
import UIKit
import Foundation
import Parse
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
var userLocationParse = PFGeoPoint(latitude: 47.49, longitude: 19.06)
#IBOutlet weak var nmapview: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
let location = CLLocationCoordinate2D(latitude: 47.49, longitude: 19.06)
let span = MKCoordinateSpanMake(0.03, 0.03)
let region = MKCoordinateRegion(center: location, span: span)
nmapview.setRegion(region, animated: true)
nmapview.showsPointsOfInterest = false
nmapview.showsUserLocation = true
displayMarkers()
}
func displayMarkers() -> Void {
//GET PIN DATA HERE
var query = PFQuery(className: "Places")
query.whereKey("PlaceLocation", nearGeoPoint: userLocationParse)
query.limit = 30
let foundPlaces = query.findObjects()
//GETTING PFGEOLOCATIONS AND PUTTING THEM ON MAP AS ANNOTATIONS
//Loading pin details
var annotationQuery = PFQuery(className: "Places")
annotationQuery.whereKey("PlaceLocation", nearGeoPoint: userLocationParse)
annotationQuery.findObjectsInBackgroundWithBlock {
(posts, error) -> Void in
if error == nil {
// The find succeeded.
//println("Successful query for annotations")
let myPosts = posts as! [PFObject]
for post in myPosts {
let pinAnnotation = PinAnnotation()
let point = post["PlaceLocation"] as! PFGeoPoint
let pointName = post["PlaceName"] as! String
let pointDetails = post["PlaceDetails"] as! String
let thePinsLocation = CLLocationCoordinate2DMake(point.latitude, point.longitude)
pinAnnotation.setCoordinate(thePinsLocation)
pinAnnotation.title = pointName
pinAnnotation.subtitle = pointDetails
self.nmapview.addAnnotation(pinAnnotation)
}
} else {
// Log details of the failure
// println("Error: \(error)")
}
}
}
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if annotation is PinAnnotation {
if annotation is MKUserLocation {
//return nil so map view draws "blue dot" for standard user location
return nil
}
let reuseID = "myPin"
var pinAnnotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseID) as? MKPinAnnotationView
if pinAnnotationView == nil {
pinAnnotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseID)
pinAnnotationView!.pinColor = .Purple
pinAnnotationView!.canShowCallout = true
pinAnnotationView!.animatesDrop = true
pinAnnotationView!.rightCalloutAccessoryView = UIButton.buttonWithType(.DetailDisclosure) as! UIButton
} else {
pinAnnotationView!.annotation = annotation
}
return pinAnnotationView
}
return nil
}
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!) {
if control == view.rightCalloutAccessoryView{
performSegueWithIdentifier("infoViewController", sender: self)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Also I created a class for "PinAnnotation" for use with the pins. Not sure if redundant but some tutorials on the subject brought it up as necessary.
import UIKit
import MapKit
import UIKit
class PinAnnotation: NSObject, MKAnnotation {
private var coord: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 90.0, longitude: 0.0)
var coordinate: CLLocationCoordinate2D {
get {
return coord
}
}
var title: String = "North Pole"
var subtitle: String = "Santa's house"
func setCoordinate(newCoordinate: CLLocationCoordinate2D) {
self.coord = newCoordinate
}
}
On the basis of what you describe, it sounds like the delegate of the map view has not been set. You can set it in IB by going to the outlets inspector. You can set it programmatically with:
nmapview.delegate = self
I have MKAnnotations set up on a map, but I would like to change the color of the annotations for different scenario's. Is there a way to change the color of the annotation?
Here is my code below, how would I implement the color change?
override func viewDidAppear(animated: Bool) {
var annotationQuery = PFQuery(className: "Post")
currentLoc = PFGeoPoint(location: MapViewLocationManager.location)
//annotationQuery.whereKey("Location", nearGeoPoint: currentLoc, withinMiles: 10)
annotationQuery.whereKeyExists("Location")
annotationQuery.findObjectsInBackgroundWithBlock {
(points, error) -> Void in
if error == nil {
// The find succeeded.
println("Successful query for annotations")
// Do something with the found objects
let myPosts = points as! [PFObject]
for post in myPosts {
let point = post["Location"] as! PFGeoPoint
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2DMake(point.latitude, point.longitude)
annotation.title = post["title"] as! String!
annotation.subtitle = post["username"] as! String!
self.mapView.addAnnotation(annotation)
}
} else {
// Log details of the failure
println("Error: \(error)")
}
}
You can use custom images for annotation view or use predefined MKPinAnnotationView with pinColor. But pinColors limited to Red, Green and Purple.
Some example:
import UIKit
import MapKit
class Annotation: NSObject, MKAnnotation
{
var coordinate: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
var custom_image: Bool = true
var color: MKPinAnnotationColor = MKPinAnnotationColor.Purple
}
class ViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
self.mapView.delegate = self;
let annotation = Annotation.new()
mapView.addAnnotation(annotation)
let annotation2 = Annotation.new()
annotation2.coordinate = CLLocationCoordinate2D(latitude: 0.0, longitude: 1.0)
annotation2.custom_image = false
mapView.addAnnotation(annotation2)
let annotation3 = Annotation.new()
annotation3.coordinate = CLLocationCoordinate2D(latitude: 1.0, longitude: 0.0)
annotation3.custom_image = false
annotation3.color = MKPinAnnotationColor.Green
mapView.addAnnotation(annotation3)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if (annotation is MKUserLocation) {
return nil
}
var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
if anView == nil {
if let anAnnotation = annotation as? Annotation {
if anAnnotation.custom_image {
let reuseId = "custom_image"
anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
anView.image = UIImage(named:"custom_image")
}
else {
let reuseId = "pin"
let pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView.pinColor = anAnnotation.color
anView = pinView
}
}
anView.canShowCallout = false
}
else {
anView.annotation = annotation
}
return anView
}
}
Update:
Set delegate for mapView in viewDidLoad
You have to set it in the viewForAnnotation method.
In this tutorial is quite well explained how doing it.
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.