MapKit in Swift, Part 2 - swift

I'm trying work with Map Kit in Swift. I try to display the area on the map, one pin (MKPinAnnotationView) and the current position. All display fine. I try to add Disclosure Button and intercept tapping on it. Disclosure Button added, but does not work intercept tapping.
Function pinPressed with method calloutAccessoryControlTapped not work....
This is a sample code:
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mainMapView: MKMapView!
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
var objectLatitude = 53.204526
var objectLongitude = 50.111751
var currentLatitude = 53.203715
var currentLongitude = 50.160374
var latDelta = 0.05
var longDelta = 0.05
var currentLocationSpan: MKCoordinateSpan = MKCoordinateSpanMake(latDelta, longDelta)
var currentLocation: CLLocationCoordinate2D = CLLocationCoordinate2DMake(locationManager.location.coordinate.latitude, locationManager.location.coordinate.longitude)
var currentRegion: MKCoordinateRegion = MKCoordinateRegionMake(currentLocation, currentLocationSpan)
self.mainMapView.setRegion(currentRegion, animated: true)
var objectLocation: CLLocationCoordinate2D = CLLocationCoordinate2DMake(objectLatitude, objectLongitude)
var objectAnnotation = MKPointAnnotation()
objectAnnotation.coordinate = objectLocation
objectAnnotation.title = "St. George's Church"
objectAnnotation.subtitle = "Church of the Great Martyr St. George"
self.mainMapView.addAnnotation(objectAnnotation)
}
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if annotation is MKUserLocation {
//return nil so map view draws "blue dot" for standard user location
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
pinView!.pinColor = .Purple
pinView!.rightCalloutAccessoryView = UIButton.buttonWithType(.DetailDisclosure) as UIButton
}
else {
pinView!.annotation = annotation
}
return pinView
}
func pinPressed(mapView: MKMapView!, annotationView: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == annotationView.rightCalloutAccessoryView {
println("Disclosure Pressed!")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}

Just updating the calloutAccessoryControlTapped delegate method, because i try it today (09/06/2015) and not works. This input field changed: annotationView view: MKAnnotationView!
//Click on left or right button
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!)
{
let anotation = view.annotation as! MyAnnotation
if (control == view.rightCalloutAccessoryView)
{
println("Button right pressed!")
}
else if (control == view.leftCalloutAccessoryView)
{
println("Button left pressed!")
}
}

The calloutAccessoryControlTapped delegate method must be named mapView(annotationView:calloutAccessoryControlTapped:).
You can't use your own name like pinPressed(...).
This applies to any delegate method and is dictated by the protocol.
So it should be:
func mapView(mapView: MKMapView!, annotationView: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == annotationView.rightCalloutAccessoryView {
println("Disclosure Pressed!")
}
}

Related

Make mutliple pin annotations buttons to segue to an other view controller (swift 3)

I have two pin annotations on my map. I created a info button to perform the segue. But the button appears only on one annotation. Can anyone help me please? For the annotations I created a function that I put into the viewdidload method.
Here`s the code:
import UIKit
import MapKit
class MapVC: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
var locManager: CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
meinkartenPunkt1()
meinkartenPunkt2()
locManager = CLLocationManager()
locManager.requestWhenInUseAuthorization()
// Do any additional setup after loading the view.
mapView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
func mapView(_ mapView: MKMapView,didUpdate userLocation: MKUserLocation){
mapView.region.center=userLocation.coordinate
mapView.showAnnotations(mapView.annotations, animated: true)
}
func meinkartenPunkt1() {
let breite: CLLocationDegrees = 8.737653
let länge: CLLocationDegrees = 47.504333
let Koordinaten = CLLocationCoordinate2DMake(länge, breite)
let Span = MKCoordinateSpanMake(0.01, 0.01)
let Region = MKCoordinateRegionMake(Koordinaten, Span)
mapView.setRegion(Region, animated: true)
let Stecknadel = MKPointAnnotation()
Stecknadel.coordinate = Koordinaten
Stecknadel.title = "Heiligberg"
mapView.addAnnotation(Stecknadel)
}
func meinkartenPunkt2() {
let breite: CLLocationDegrees = 8.734345
let länge: CLLocationDegrees = 47.508456
let Koordinaten = CLLocationCoordinate2DMake(länge, breite)
let Span = MKCoordinateSpanMake(0.01, 0.01)
let Region = MKCoordinateRegionMake(Koordinaten, Span)
mapView.setRegion(Region, animated: true)
let Stecknadel = MKPointAnnotation()
Stecknadel.coordinate = Koordinaten
Stecknadel.title = "Kanti Rychenberg"
mapView.addAnnotation(Stecknadel)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?{
if annotation is MKUserLocation {return nil}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
let calloutButton = UIButton(type: .detailDisclosure)
pinView!.rightCalloutAccessoryView = calloutButton
pinView!.sizeToFit()
}
else {
pinView!.annotation = annotation
}
return pinView
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView,
calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView {
performSegue(withIdentifier: "bookDetails", sender: self)
}
}
}
When looking at your source code, I cannot directly see an answer, however I see an immediate problem. You do some important setup on the pinView, while it is nil. To be honest, this code certainly crashes, if it is ever reached:
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
Luckily for you, pinView never is nil however, as the mapView creates the pinView successfully. What you probably want to do, is to set the calloutButton, if it is not set. So instead of if pinView == nil you write:
if pinView?.rightCalloutAccessoryView == nil {
// Initialize the rightCalloutAccessoryView here
}
Tip: In general you should avoid force unwraps with ! as it leads to crashes. Try to use optional chaining with ? instead.

Pass the url from the marker into the controller

I'm doing the app for viewing IP cameras and want to add cameras to the map so you can click on the desired marker and go to see the desired camera. I have a map and PlayerViewController which reproduce a webcam.
Now each marker only transmits the first stream of the webcam. Help me. How to make different webcam worked?
ViewController
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
var moscow: [(name: String, URLs:String, img:String, latitude: Double, longitude: Double)] =
[("cam1", "http://example/1.m3u8", "1.jpg", 55.753989, 37.620235),
("cam2", "http://example/2.m3u8", "2.jpg", 55.741308, 37.653914),
("cam3","http://example/3.m3u8","3.jpg", 55.742468, 37.629292)]
override func viewDidLoad() {
super.viewDidLoad()
var latitudes = moscow.map({ $0.latitude })
var longitudes = moscow.map({ $0.longitude })
var annotations = moscow.map({ $0.name })
for i in 0...2 {
let coordinate = CLLocationCoordinate2DMake(latitudes[i], longitudes[i])
let span = MKCoordinateSpanMake(0.003, 0.003)
let region = MKCoordinateRegionMake(coordinate, span)
mapView.setRegion(region, animated:true)
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
annotation.title = annotations[i]
self.mapView.addAnnotation(annotation)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
print(#function)
}
// Called when the annotation was added
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView?.animatesDrop = true
pinView?.canShowCallout = true
pinView?.isDraggable = true
pinView?.pinColor = .purple
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) {
print(#function)
if control == view.rightCalloutAccessoryView {
performSegue(withIdentifier: "toTheMoon", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toTheMoon" {
let controller = segue.destination as! PlayerViewController
var urlll = moscow.map({ $0.URLs })
for i in 0...2 {
controller.webcamURL = urlll[i] // only first cam play
}
}
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, didChange newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
if newState == MKAnnotationViewDragState.ending {
let droppedAt = view.annotation?.coordinate
print(droppedAt)
}
}
}
PlayerViewController
import UIKit
import AVFoundation
import AVKit
class PlayerViewController: AVPlayerViewController {
var webcamURL: String!
var webcamTitle: String!
override func viewDidLoad() {
super.viewDidLoad()
self.title = webcamTitle
let url = URL(string: webcamURL)
player = AVPlayer(url: url!)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
player!.play()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.player!.pause()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
player = nil
}
}
First of All MKAnnotation is a Protocol so you can implement this protocol in your model class, lets say "Camera"
import UIKit
import MapKit
class Camera: NSObject, MKAnnotation {
var name: String = ""
var urlString :String = ""
var coordinate: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 0, longitude: 0)
var imageName : String = ""
init(name:String,camUrl:String,imageNamed:String,latitude:CLLocationDegrees,longitude:CLLocationDegrees) {
super.init()
self.name = name
self.urlString = camUrl
self.imageName = imageNamed
guard latitude != 0 && longitude != 0 else
{
return
}
guard latitude.isNaN || longitude.isNaN else
{
return
}
self.coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
}
// Title and subtitle for use by selection UI.
public var title: String? {
get{
return self.name
}
}
}
Then you can reduce your ViewController code like this
import UIKit
import MapKit
class ViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
var moscow: [Camera] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.moscow = [Camera(name: "cam1", camUrl: "http://example/1.m3u8", imageNamed: "1.jpg", latitude: 55.753989, longitude: 37.620235),
Camera(name: "cam2", camUrl: "http://example/2.m3u8", imageNamed: "2.jpg", latitude: 55.741308, longitude: 37.653914),
Camera(name: "cam3", camUrl: "http://example/3.m3u8", imageNamed: "3.jpg", latitude: 55.742468, longitude: 37.629292)]
self.mapView.addAnnotations(self.moscow)
self.mapView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension ViewController : MKMapViewDelegate
{
func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
print(#function)
}
// Called when the annotation was added
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView?.animatesDrop = true
pinView?.canShowCallout = true
pinView?.isDraggable = true
pinView?.pinColor = .purple
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) {
print(#function)
let camera = view.annotation as! Camera
if control == view.rightCalloutAccessoryView {
performSegue(withIdentifier: "toTheMoon", sender: camera)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toTheMoon" {
let controller = segue.destination as! PlayerViewController
controller.webcamURL = (sender as! Camera).urlString
controller.webcamTitle = (sender as! Camera).name
}
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, didChange newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
if newState == MKAnnotationViewDragState.ending {
let droppedAt = view.annotation?.coordinate
print(droppedAt)
}
}
}
Hope this helps

Swift performSegue going to Xcode

I am trying to perform a Segue between two UI Views I have correctly typed the identifier for the segue as can be seen Here
This is my function, with the same identifier "no" but when the button is clicked in the simulator it simply shows This (It looks like it is showing the stack in bottom left?)
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView {
performSegue(withIdentifier: "no", sender:self)
}
}
I have attached my full code incase further analysis is needed. Thanks for your help.
View Controller:
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate,CLLocationManagerDelegate {
#IBOutlet weak var MapView: MKMapView!
let manager = CLLocationManager()
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//let location = locations[0]
//let span:MKCoordinateSpan = MKCoordinateSpanMake(0.02, 0.02)
//let myLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
}
override func viewDidLoad() {
super.viewDidLoad()
// tracking user's location
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
// Setting up Map
let distanceSpan:CLLocationDegrees = 2000
MapView.setRegion(MKCoordinateRegionMakeWithDistance(CLLocationCoordinate2DMake(-39.0556253, 174.0752278), distanceSpan, distanceSpan), animated: true)
MapView.showsUserLocation = true
MapView.delegate = self
// artwork on map
let windwandcoord: CLLocationCoordinate2D = CLLocationCoordinate2DMake(-39.055961,174.072288)
let artworkPin = Artwork(title:"Wind Wand",locationName:"Majestic",discipline:"Statue",
coordinate:windwandcoord)
MapView.addAnnotation(artworkPin)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
{
if annotation is MKUserLocation {return nil}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
pinView!.calloutOffset = CGPoint(x: -5, y: 5)
let calloutButton = UIButton(type: .detailDisclosure)
pinView!.rightCalloutAccessoryView = calloutButton
pinView!.sizeToFit()
}
else {
pinView!.annotation = annotation
}
return pinView
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView {
performSegue(withIdentifier: "no", sender:self)
}
}
}
Any help appreciated.
See the solid blue bar in the gutter in your screen shot?
It is a breakpoint. When the path of execution reaches a breakpoint that is active (solid blue like this), we pause there. That is what a breakpoint is for.
If you don't want that to happen, drag the breakpoint out of the gutter.

How To make Map Pins Animate drop? Swift 2.2 IOS 9

I have a basic setup here of a map in my view, I'm trying to make the pins animate a drop...Just like when you press & hold in the maps app and the pin drops to the location. So when I get in the view all the pins will animate a drop to their location and I really dont know how to do that . If anyone can guide me to the correct code I need to add that will be great!
Here is the Current Code I have :
class FirstViewController: UIViewController,MKMapViewDelegate, CLLocationManagerDelegate{
#IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.mapView.showsUserLocation = true
let LitzmanLocation = CLLocationCoordinate2DMake(32.100668,34.775192)
// Drop a pin
let Litzman = MKPointAnnotation()
Litzman.coordinate = LitzmanLocation
Litzman.title = "Litzman Bar"
Litzman.subtitle = "Nemal Tel Aviv St'"
mapView.addAnnotation(Litzman)}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
//Dispose of resources that can be re created.
}
//Mark:
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.1, longitudeDelta: 0.1))
self.mapView.setRegion(region, animated: true)
self.locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError)
{
print("Errors: " + error.localizedDescription)
}
Before all I am not maintaining any standards and I just have one of the solution for your problem and I am learning swift and mapKit by solving others problems.
Here I have given some sample code and I have added mapView and UITapGestureRecognizer through the Object library.
For adding annotation like dropping from top
pinView!.animatesDrop = true
in the viewForAnnotation delegation method.And addAnnotation method will call to add the annotation when you tap on the map.
For animating all the annotation
I have implemented regionDidChangeAnimated delegate method and just remove and add again all the annotations.
import UIKit
import MapKit
import CoreLocation
class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
print("viewDidLoad")
self.mapView.delegate = self
self.locationManager.delegate = self
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.mapView.showsUserLocation = true
let locationData = [
//Walker Art Gallery
["name": "Walker Art Gallery",
"latitude": 12,
"longitude": 79],
//Liver Buildings
["name": "Liver Buildings",
"latitude": 13,
"longitude": 77],
//St George's Hall
["name": "St George's Hall",
"latitude": 14,
"longitude": 77]
]
var annotations = [MKPointAnnotation]()
for each in locationData {
let latitude = CLLocationDegrees(each["latitude"] as! Double)
let longitude = CLLocationDegrees(each["longitude"] as! Double)
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
let name = each["name"] as! String
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
annotation.title = "\(name)"
annotations.append(annotation)
}
mapView.addAnnotations(annotations)
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
print("viewForAnnotation \(annotation.title)")
if annotation is MKUserLocation {
return nil
}
let reuseID = "pin"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseID) as? MKPinAnnotationView
if(pinView == nil) {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseID)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
}
return pinView
}
#IBAction func addAnnotation(sender: UITapGestureRecognizer) {
if sender.state == .Ended {
let location = sender.locationInView(mapView)
let coordinate = mapView.convertPoint(location,toCoordinateFromView: mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
mapView.addAnnotation(annotation)
}
}
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
print("regionDidChangeAnimated")
let annotations = self.mapView.annotations
self.mapView.removeAnnotations(annotations)
self.mapView.addAnnotations(annotations)
}
}
EDIT
For your case in the viewDidLoad method add this
self.mapView.delegate = self
For annotating the MKAnnotation you have to implement the below delegate method
//Annotation view
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!.canShowCallout = true
pinView!.animatesDrop = true
}
return pinView
}
After for annotating all the annotation you have to implement below delegate method.
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
let annotations = self.mapView.annotations
self.mapView.removeAnnotations(annotations)
self.mapView.addAnnotations(annotations)
}
And I am assuming you know how to add annotation on map tap...
EDIT2
Here is what you need my friend.
In the viewDidLoad add one notification observer as follows.
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(didBecomeActive), name: UIApplicationDidBecomeActiveNotification, object: nil)
And lastly change that regionDidChangeAnimated to didBecomeActive as below
func didBecomeActive() {
let annotations = self.mapView.annotations
self.mapView.removeAnnotations(annotations)
self.mapView.addAnnotations(annotations)
}
In Objective C:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// Handle any custom annotations.
if ([annotation isKindOfClass:[MKPointAnnotation class]])
{
// Try to dequeue an existing pin view first.
MKPinAnnotationView *pinView = (MKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if (!pinView)
{
// If an existing pin view was not available, create one.
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.animatesDrop = YES;
pinView.pinTintColor = [UIColor blueColor];
} else {
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}

How to disallow rotation on MKMapView but show heading?

For my project, I would like to put on a MKMapView the heading of the user without rotating the map (with the blue cone).
Here's a gist
Furthermore, with mapView.setUserTrackingMode(MKUserTrackingMode.FollowWithHeading, animated: true) enable, I can't navigate trough my map.
I tried to set the trackingMode on the mapView:didChangeUserTrackingMode but It's not working.
Any idea ?
I had the same issue and resolved it by using CLLocationManager and locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) method:
class MyViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
weak var userAnnotationView: MKAnnotationView?
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
mapView.showsUserLocation = true
mapView.delegate = self
locationManager.delegate = self
locationManager.startUpdatingHeading()
}
}
// MARK: - MKMapViewDelegate
extension MyViewController: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if let annotation = annotation as? MKUserLocation {
// User
let reuseIdentifier = "UserAnnotationView"
let annotationView: MKAnnotationView
if let view = mapView.dequeueReusableAnnotationView(withIdentifier: reuseIdentifier) {
annotationView = view
} else {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseIdentifier)
}
annotationView.image = UIImage(named: "userLocationWithoutHeading")
userAnnotationView = annotationView
return annotationView
} else {
return nil
}
}
}
// MARK: - CLLocationManagerDelegate
extension MyViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
guard let userAnnotationView = userAnnotationView else { return }
userAnnotationView.image = UIImage(named: "arrowUp")
let rotationAngle = heading.magneticHeading * Double.pi / 180.0
userAnnotationView.transform = CGAffineTransform(rotationAngle: CGFloat(rotationAngle))
}
}