Showing a new viewController when tapping on a mark on a mapView? - ios

I have a mapView with pins showing users positions, tapping on them I show some info about users and places. I'd like to implement a feature in wich by tapping on those info little panel, I can navigate to another viewController from which
send a personal message via Parse. Even a button could be fine.
this is my mapViwController code
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!)
{
let point = PFGeoPoint(latitude:manager.location.coordinate.latitude, longitude:manager.location.coordinate.longitude)
let location = locations.last as! CLLocation
let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1))
self.mapView.setRegion(region, animated: true)
CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: {(placemarks, error)->Void in
if (error != nil)
{
println("Error: " + error.localizedDescription)
return
}
if placemarks.count > 0
{
let pm = placemarks[0] as! CLPlacemark
self.displayLocationInfo(pm, point: point)
}
else
{
println("Error with the data.")
}
})
}
func displayLocationInfo(placemark: CLPlacemark, point: PFGeoPoint)
{
self.locationManager.stopUpdatingLocation()
self.createAnnotations(point, address: "\(placemark.locality) \(placemark.administrativeArea) \(placemark.postalCode) \(placemark.country)")
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!)
{
println("Error: " + error.localizedDescription)
}
// MARK: - Create Annotation
func createAnnotations(point: PFGeoPoint, address: String)
{
var query = PFUser.query()
var withinKms = NSUserDefaults.standardUserDefaults().objectForKey("withinKms") as! Double
// query?.whereKey("location", nearGeoPoint: point, withinKms: withinKms) // also withinKilometers if wanted
query?.whereKey("location", nearGeoPoint: point, withinKilometers: withinKms)
query?.limit = 10
query?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if error == nil
{
for(var i = 0; i < objects!.count; i++)
{
let user = objects![i] as! PFUser
var myHomePin = MKPointAnnotation()
let userPoint = user["location"] as! PFGeoPoint
myHomePin.coordinate = CLLocationCoordinate2DMake(userPoint.latitude, userPoint.longitude)
myHomePin.title = user.username
myHomePin.subtitle = address
self.mapView.addAnnotation(myHomePin)
}
}
else
{
println("Error: " + error!.localizedDescription)
}
})
}
Anbu's Answer
#IBOutlet weak var mapView: MKMapView!
//************************************************
func mapView(mapView: mapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!) {
println("disclosure pressed: \(view.annotation.title)")
// do your stuff here
// #IBAction func startChat(sender: UIButton)
// add your segue
if control == annotationView.rightCalloutAccessoryView {
self.performSegueWithIdentifier("nextViewController", sender: self)
}
}
//************************************************

receive mapView delegate callback method
//if you pressed the annotation view the following method is called
func mapView(mapView: MKMapView!, didSelectAnnotationView view: MKAnnotationView!)
// if you press the calloutButton the following method is called
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!)
for example
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!) {
println("disclosure pressed: \(view.annotation.title)")
// do your stuff here
// add your segue
if control == annotationView.rightCalloutAccessoryView {
self.performSegueWithIdentifier("nextViewController", sender: self)
}
}

Please try with
annotationView.canShowCallout = YES;
and implement the method in below delegate:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
NSLog(#"calloutAccessoryControlTapped: annotation = %#", view.annotation);
MyDetailViewController *detailView=[[MyDetailViewController alloc] initWithNibName:#"MyDetailViewController" bundle:nil];
//here, can set annotation info in some property of detailView
[[self navigationController] pushViewController:detailView animated:YES];
[detailView release];
}

Related

How to display customer callout screens on a map using Swift and Xcode

I am fairly new to IOS development, and I am working on creating a map to display different venues from a JSON file which works like a charm. Now, what I want to do is, once a user clicks a pin, I want a callout view to be displayed at the bottom of the map that shows the Venue's logo on the left, and the following on the right:
a phone number that's clickable so call them directly, a website url that's clickable to access the website, and finally, a directions button to open the map to show directions to the Venue.
Once a user clicks a different pin, then the information about that new venue is displayed.
Here is the portion of the code that I think needs edits, and below is the full code
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
{
if let annotation = annotation as? Venue {
let identifier = "pin"
var view: MKPinAnnotationView
if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView {
dequeuedView.annotation = annotation
view = dequeuedView
} else {
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.calloutOffset = CGPoint(x: -5, y: 5)
view.rightCalloutAccessoryView = UIButton(type: .detailDisclosure) as UIView
}
return view
}
return nil
}
Please help me with step by step instructions. I am having a hard time getting around Swift.
THANKS A BUNCH!
import UIKit
import CoreLocation
import MapKit
//import SwiftyJSON
struct Place: Codable {
let id: Int
let name, address, number, imageURL: String
let lat, long: Double
enum CodingKeys: String, CodingKey {
case id, name, address, number
case imageURL = "imageUrl"
case lat, long
}
}
class YogaViewController: UIViewController {
// MARK: - Properties
var locationManager: CLLocationManager!
var mapView: MKMapView!
let centerMapButton: UIButton = {
let button = UIButton(type: .system)
button.setImage(#imageLiteral(resourceName: "location-arrow-flat").withRenderingMode(.alwaysOriginal), for: .normal)
button.addTarget(self, action: #selector(handleCenterLocation), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
// MARK: - Init
override func viewDidLoad() {
super.viewDidLoad()
configureLocationManager()
configureMapView()
enableLocationServices()
// mapView.addAnnotations(venues)
// //JSON STUFF
let jsonUrlString = "https://www.elev8dfw.com/Gyms.json"
// let jsonUrlString = "https://www.elev8dfw.com/Venues.json"
// let jsonUrlString = "https://api.letsbuildthatapp.com/jsondecodable/course"
guard let url = URL(string: jsonUrlString) else {return}
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else { return }
do {
let places = try JSONDecoder().decode([Place].self, from: data)
for place in places {
// print(place.lat)
// print(place.long)
let sampleStarbucks = Venue(title: place.name, locationName: place.address, coordinate: CLLocationCoordinate2D(latitude: place.lat, longitude: place.long))
self.mapView.addAnnotation(sampleStarbucks)
}
} catch let jsonErr{
print("Error serializing json: ", jsonErr)
}
}.resume()
mapView.delegate = self
}
// MARK: - Selectors
#objc func handleCenterLocation() {
centerMapOnUserLocation()
centerMapButton.alpha = 0
}
// MARK: - Helper Functions
func configureLocationManager() {
locationManager = CLLocationManager()
locationManager.delegate = self
}
func configureMapView() {
mapView = MKMapView()
mapView.showsUserLocation = true
mapView.delegate = self
mapView.userTrackingMode = .follow
view.addSubview(mapView)
mapView.frame = view.frame
view.addSubview(centerMapButton)
centerMapButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -100).isActive = true
centerMapButton.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20).isActive = true
centerMapButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
centerMapButton.widthAnchor.constraint(equalToConstant: 50).isActive = true
centerMapButton.layer.cornerRadius = 50 / 2
centerMapButton.alpha = 0
}
func centerMapOnUserLocation() {
guard let coordinate = locationManager.location?.coordinate else { return }
let region = MKCoordinateRegion(center: coordinate, latitudinalMeters: 4000, longitudinalMeters: 4000)
mapView.setRegion(region, animated: true)
}
}
// MARK: - MKMapViewDelegate
extension YogaViewController: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
UIView.animate(withDuration: 0.5) {
self.centerMapButton.alpha = 1
}
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
{
if let annotation = annotation as? Venue {
let identifier = "pin"
var view: MKPinAnnotationView
if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView {
dequeuedView.annotation = annotation
view = dequeuedView
} else {
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.calloutOffset = CGPoint(x: -5, y: 5)
view.rightCalloutAccessoryView = UIButton(type: .detailDisclosure) as UIView
}
return view
}
return nil
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
let location = view.annotation as! Venue
let launchOptions = [MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving]
location.mapItem().openInMaps(launchOptions: launchOptions)
}
}
// MARK: - CLLocationManagerDelegate
extension YogaViewController: CLLocationManagerDelegate {
func enableLocationServices() {
switch CLLocationManager.authorizationStatus() {
case .notDetermined:
print("Location auth status is NOT DETERMINED")
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
centerMapOnUserLocation()
case .restricted:
print("Location auth status is RESTRICTED")
case .denied:
print("Location auth status is DENIED")
case .authorizedAlways:
print("Location auth status is AUTHORIZED ALWAYS")
case .authorizedWhenInUse:
print("Location auth status is AUTHORIZED WHEN IN USE")
locationManager.startUpdatingLocation()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
centerMapOnUserLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
self.mapView.showsUserLocation = true
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
guard locationManager.location != nil else { return }
centerMapOnUserLocation()
}
}
If you are attempting to open a custom UIView coming up from the bottom upon tapping a annotation you could utilize didSelect and do something like the following:
final func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
let location = view.annotation as! Venue
// Update your new custom view with the Venue here.
// Now lets show the view
self.bottomViewConstraint.constant = 0
UIView.animate(withDuration: 0.2) {
self.view.layoutIfNeeded()
}
}
So in your storyboard. Create a UIView, set its height and width constraints. Set its bottom constraint to be a negative number so it is not showing on the screen. Create an IBOutlet to the bottom constraint (I named it bottomViewConstraint in the example code). This is a very basic example, untested, to get you started.

How to make annotation point draggable in MapKit using swift 2 and xcode 7?

It is very frustrating to find the solution for this problem. I posted the whole code to understand the problem. Please help
import UIKit
import MapKit
import CoreLocation
class LocationViewController: UIViewController,MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager()
var annotationPoint: MKPointAnnotation!
var getMovedMapCenter: CLLocation!
var myPinView:MKPinAnnotationView!
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
if #available(iOS 8.0, *) {
self.locationManager.requestWhenInUseAuthorization()
} else {
// Fallback on earlier versions
}
self.locationManager.startUpdatingLocation()
self.mapView.showsUserLocation = true
// Do any additional setup after loading the view.
}
// MARK: - Location Delegate Methods
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
let location = locations.last
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1))
self.mapView.setRegion(region, animated: true)
if(self.annotationPoint == nil)
{
self.annotationPoint = MKPointAnnotation()
getMovedMapCenter = CLLocation(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
self.annotationPoint.coordinate = getMovedMapCenter.coordinate
// self.annotationPoint.title = location_value
//self.annotationPoint.subtitle = ""
// println_debug(self.annotationPoint)
self.mapView.addAnnotation(self.annotationPoint)
}
self.locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError)
{
print("Errors: " + error.localizedDescription)
}
//MARK:- View for Annotation
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView?
{
if annotation is MKPointAnnotation {
let pinAnnotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "myPin")
pinAnnotationView.pinColor = .Purple
pinAnnotationView.draggable = true
pinAnnotationView.canShowCallout = true
pinAnnotationView.animatesDrop = true
return pinAnnotationView
}
return nil
}
//MARK:- Annotation Changed State
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, didChangeDragState newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
print("hiii")
// println_debug("End State coordinates: \(self.annotationPoint.coordinate.latitude),\(self.annotationPoint.coordinate.longitude)")
if(newState == .Ending)
{
let center = CLLocationCoordinate2D(latitude: self.annotationPoint.coordinate.latitude, longitude: self.annotationPoint.coordinate.longitude)
// self.currentLocationNameA(center)
// dispatch_async(GlobalBackgroundQueue)
// {
//
//
// }
}
}
//MARK:- update Not Get
func mapView(mapView: MKMapView,
didFailToLocateUserWithError error: NSError)
{
// AppHelper.showALertWithTag(121, title: APP_NAME, message: "Failed to get location. Please check Location setting", delegate: nil, cancelButtonTitle: "Ok", otherButtonTitle: nil)
}
}
I got stuck in this code. Becasuse didChangeDragState Delegate never called. Please help me to find a better solution for this. I am new to swift; So its hard to convert the objective c code in swift
The drag state typically changes in response to user interactions with
the annotation view. However, the annotation view itself is
responsible for changing that state as well.
replace this method and try once. may be working fine
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, didChangeDragState newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
switch (newState) {
case .Starting:
view.dragState = .Dragging
case .Ending, .Canceling:
view.dragState = .None
default: break
}
}
Replace you point annotation method with this one.
let pa = MKPointAnnotation()
pa.coordinate = placemark.location.coordinate
pa.title = placemark.name //or whatever title you like
self.mapView.addAnnotation(pa)
for more , you can see Code and Another Sample Code
pinAnnotationView.canShowCallout = false
This line solves my problem. Popup of showing "current location" was the main cause of this problem.
and these changes in code make it smooth dragging. Mehul and Vijay Answer help me in finding this solution.
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, didChangeDragState newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
switch (newState) {
case .Ending, .Canceling:
view.dragState = .None
default: break
}
}
if (annotation is MKUserLocation) {
return nil
}
let reuseId12 = "pin12"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
if pinView == nil {
pinView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId12)
pinView.image = UIImage(named:"pin-1250.png")
pinView.canShowCallout = false
pinView.draggable = true
}
else {
pinView.annotation = annotation
}
return pinView
Try this code.

Cannot change pins for images in a map

I have a map where I mark points based on Parse data. This works correctly. When I try to change the red pins of the map with a custom image, it seems that everything is OK but when I run the app in the simulator, the red pins are there and my image doesn't appear. I have tried some similar versions of the code I have with the same result. I tried to print the annotationView in the console and seems that have the image saved the line before the return. Where is the error? What I have to do to show the custom image correctly? Thanks.
import UIKit
import MapKit
import CoreLocation
import Foundation
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager()
var MapViewLocationManager:CLLocationManager! = CLLocationManager()
var currentLoc: PFGeoPoint! = PFGeoPoint()
override func viewDidLoad() {
super.viewDidLoad()
self.mapView.delegate = self
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.mapView.showsUserLocation = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
let location = locations.last
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5))
self.mapView.setRegion(region, animated: true)
self.locationManager.stopUpdatingLocation()
}
override func viewDidAppear(animated: Bool) {
let annotationQuery = PFQuery(className: "_User")
currentLoc = PFGeoPoint(location: MapViewLocationManager.location)
annotationQuery.whereKey("restaurant", equalTo: true)
annotationQuery.whereKey("restaurantPosition", nearGeoPoint: currentLoc, withinMiles: 6000)
annotationQuery.findObjectsInBackgroundWithBlock {
(posts, error) -> Void in
if error == nil {
// The find succeeded.
print("Successful query for annotations")
let myPosts = posts as [PFObject]!
for post in myPosts {
let point = post["restaurantPosition"] as! PFGeoPoint
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2DMake(point.latitude, point.longitude)
self.mapViewN(self.mapView, viewForAnnotation: annotation).annotation = annotation
self.mapView.addAnnotation(annotation)
}
} else {
// Log details of the failure
print("Error: \(error)")
}
}
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("Error: " + error.localizedDescription)
}
func mapViewN(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView {
let identifier = "pin"
// Reuse the annotation if possible
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView!.canShowCallout = true
annotationView!.image = UIImage(named: "map_marker_2")
}
else {
annotationView!.annotation = annotation
}
print(annotationView?.image)
return annotationView!
}
}
Your method map view:viewForAnnotation: is misnamed. You have
func mapViewN(mapView: MKMapView,
viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView
That N in the name does not belong there, so your delegate method will never be called.
(The method name for a delegate method must be exactly correct or the method doesn't get called. For a required delegate method you may even crash.)
It should be:
func mapView(mapView: MKMapView,
viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView
mapViewN:viewForAnnotation delegate is called?
Maybe you should rename mapViewN to mapView.
func mapViewN(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView {
->
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {

Adding accessory button on user location callout

I'm making a clickable placemark. I set the title of the placemark. Title is adress. I want If you click on that adress It will push to another View to Show Adress Number,City,Country etc. I Tried this code. But It haven't UIButton in application in placemark, why?
EDIT: If I put breakpoint to func calloutAccessoryControlTapped it isn't crashing.
func mapView(Mapa: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if annotation is MKUserLocation {
//return nil so map view draws "blue dot" for standard user location
return nil
}
var pin = "pin"
var view = Mapa.dequeueReusableAnnotationViewWithIdentifier(pin) as? MKPinAnnotationView
if view == nil {
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: pin)
view!.canShowCallout = true
view!.animatesDrop = true
var arrowButton = UIButton()
view!.rightCalloutAccessoryView = UIButton.buttonWithType(.DetailDisclosure) as! UIButton
} else {
view!.annotation = annotation
}
return view
}
func mapView(Mapa: MKMapView!, annotation: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == annotation.rightCalloutAccessoryView {
println("Pressed!")
}
}
Whole code:
import UIKit
import CoreLocation
import MapKit
class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
#IBOutlet weak var Mapa: MKMapView!
let locationManager = CLLocationManager()
var detail: UIButton!
override func viewDidLoad()
{
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
Mapa.delegate = self
Mapa.mapType = MKMapType.Standard
Mapa.showsUserLocation = true
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
//--- Find Address of Current Location ---//
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!)
{
//--- CLGeocode to get address of current location ---//
CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: {(placemarks, error)->Void in
let spanX = 0.007
let spanY = 0.007
var newRegion = MKCoordinateRegion(center: self.Mapa.userLocation.coordinate, span: MKCoordinateSpanMake(spanX, spanY))
self.Mapa.setRegion(newRegion, animated: true)
if (error != nil)
{
println("Reverse geocoder failed with error" + error.localizedDescription)
return
}
if placemarks.count > 0
{
let pm = placemarks[0] as! CLPlacemark
self.displayLocationInfo(pm)
}
else
{
println("Problem with the data received from geocoder")
}
})
}
func displayLocationInfo(placemark: CLPlacemark?)
{
if let Placemark = placemark
{
//Stop updating kvôli vydrži baterke
locationManager.stopUpdatingLocation()
let location = self.locationManager.location
var latitude: Double = location.coordinate.latitude
var longitude: Double = location.coordinate.longitude
let adresa = (Placemark.thoroughfare != nil) ? Placemark.thoroughfare : "Ulica: "
let cislo = (Placemark.subThoroughfare != nil) ? Placemark.subThoroughfare : "Číslo ulice:"
let mesto = (Placemark.locality != nil) ? Placemark.locality : "Mesto: "
let stat = (Placemark.country != nil) ? Placemark.country : "Štát: "
var coordinates:CLLocationCoordinate2D = placemark!.location.coordinate
let theLocation: MKUserLocation = Mapa.userLocation
theLocation.title = adresa
println("GPS Súradnice :: \(latitude), \(longitude)")
println(mesto)
println(adresa)
println(cislo)
println(stat)
}
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!)
{
println("Chyba pri aktualizovaní lokácie " + error.localizedDescription)
}
func mapView(Mapa: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if annotation is MKUserLocation {
//return nil so map view draws "blue dot" for standard user location
return nil
}
var pin = "pin"
var view = Mapa.dequeueReusableAnnotationViewWithIdentifier(pin) as? MKPinAnnotationView
if view == nil {
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: pin)
view!.canShowCallout = true
view!.animatesDrop = true
var arrowButton = UIButton()
view!.rightCalloutAccessoryView = UIButton.buttonWithType(.DetailDisclosure) as! UIButton
} else {
view!.annotation = annotation
}
return view
}
func mapView(Mapa: MKMapView!, annotation: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == annotation.rightCalloutAccessoryView {
println("Pressed!")
}
}
}
You want to put an accessory button on the callout of the blue dot (user location).
In the viewForAnnotation delegate method, you do have code that creates an annotation view and sets the rightCalloutAccessoryView but at the top of the method there is this code:
func mapView(Mapa: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if annotation is MKUserLocation {
//return nil so map view draws "blue dot" for standard user location
return nil
}
The map's user location annotation is of type MKUserLocation so when the map view calls viewForAnnotation for it, this code returns nil for it which the map view interprets as "display the default view and callout for this annotation". The default callout only shows a title and subtitle.
The code that creates a custom view and sets rightCalloutAccessoryView never executes.
To set a rightCalloutAccessoryView, you need a reference to the actual annotation view object.
You could remove that return nil for the MKUserLocation but then you'll get a standard pin instead of an animated blue dot.
You can't create your own instance of the animated blue dot view because that class is private.
So you can't create or get access to the user location annotation view in the viewForAnnotation delegate method.
A place where you can reliably get access to the actual user location annotation view is in the didAddAnnotationViews delegate method. I suggest this method because it means an annotation view has actually been created and is on the screen.
In this method, call the map view's viewForAnnotation instance method and pass it its userLocation annotation and then set the view's rightCalloutAccessoryView:
func mapView(mapView: MKMapView!, didAddAnnotationViews views: [AnyObject]!) {
if let ulav = mapView.viewForAnnotation(mapView.userLocation) {
ulav.rightCalloutAccessoryView = UIButton.buttonWithType(.DetailDisclosure) as! UIButton
}
}
Unrelated to the callout button not appearing but:
Your calloutAccessoryControlTapped delegate method is named wrong and will not get called when the button is tapped.
Your method is named mapView(annotation:calloutAccessoryControlTapped).
The annotation parameter must be named annotationView and even though naming the map view parameter Mapa will work, I suggest sticking to the signature given in the documentation so the revised method would be:
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!) {
if control == annotationView.rightCalloutAccessoryView {
println("Pressed!")
}
}

locate user location in Swift

I try to add Current Location in to the map by using CLLocationmanager, but when I try to call the func mapView.StartUpdateLocation some how the delegate protocol " didUpdateLocation " is not to be called, any know how can I fix this ? Thanks
import UIKit
import MapKit
class mapViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
#IBOutlet var mapView: MKMapView!
var restaurant:Restaurant!
var locationManager = CLLocationManager()
var current: CLPlacemark!
override func viewDidLoad()
{
super.viewDidLoad()
mapView.delegate = self
self.locationManager.requestAlwaysAuthorization()
// convert address to coordinate
let geoCoder = CLGeocoder()
geoCoder.geocodeAddressString(restaurant.location, completionHandler: { (placemarks, error) -> Void in
if error != nil
{
print(error)
return
}
if placemarks.count > 0
{
let placemark = placemarks[0] as CLPlacemark
// add annotation
let annotation = MKPointAnnotation()
annotation.coordinate = placemark.location.coordinate
annotation.title = self.restaurant.name
annotation.subtitle = self.restaurant.type
self.mapView.showAnnotations([annotation], animated: true)
self.mapView.selectAnnotation(annotation, animated: true)
self.mapView.showsUserLocation = true // add to show user location
}
})
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func currentLocation(sender: AnyObject)
{
if ( CLLocationManager.locationServicesEnabled())
{
println("Location service is on ")
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.stopUpdatingLocation()
locationManager.startUpdatingLocation()
}else
{
println("Location service is not on ")
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!)
{
CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: { (placemarks, error) -> Void in
if error != nil
{
print("error")
}
if placemarks.count > 0
{
self.current = placemarks[0] as CLPlacemark
let annotation = MKPointAnnotation()
annotation.coordinate = self.current.location.coordinate
self.mapView.showAnnotations([annotation], animated: true)
self.mapView.selectAnnotation(annotation, animated: true)
}
else
{
print("I dont know what the fuck is the error")
}
})
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
println(error.localizedDescription)
}
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView!
{
let indentifier = "My Pin"
if annotation.isKindOfClass(MKUserLocation){ return nil }
// Resuse Annotation if possiable
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(indentifier)
if annotationView == nil
{
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: indentifier)
annotationView.canShowCallout = true // tell annotation can display
}
let iconImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 53, height: 53)) // create left icon image for annotation view
iconImageView.image = UIImage(named: restaurant.image)
annotationView.leftCalloutAccessoryView = iconImageView
return annotationView
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
There is a change between iOS7 & 8 about GPS localisation. Please read this article.
http://matthewfecher.com/app-developement/getting-gps-location-using-core-location-in-ios-8-vs-ios-7/
Maybe you have not added these infos to your .plist
<key>NSLocationAlwaysUsageDescription</key>
<string>Your message goes here</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Your message goes here</string>
Please check once below keys entered in info.plist
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
and set
var _locationManager = CLLocationManager()
_locationManager.delegate = self
_locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
_locationManager.requestAlwaysAuthorization()
in viewDidLoad()

Resources