Get the MKAnnotationView of user location - ios

I'm trying to get the MKAnnotationView that displays the user location (blue dot) in MapKit to add a custom gesture recognizer. Is this possible?
I've tried via the delegate method but I don't know how to dequeue the view when I don't have the identifier string. If I had the identifier I could probably do something like the code below;
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
let userLocationAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "??", for: annotation)
userLocationAnnotationView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.handleStuff)))
return userLocationAnnotationView
}
}
EDIT
Ah, been stuck on this for hours and found the solution directly after I posted. I found two different ways of solving it with delegate methods. The first way could be via didSelect:
func mapView(_ mapView: MKMapView,
didSelect view: MKAnnotationView){
if view.annotation is MKUserLocation {
// User clicked on the blue dot
}
}
Or if a gesture recognizer is needed it could be done as below. Should probably add a check if the gesture recognizer already have been added since this function gets called every time an annotation view is added.
func mapView(_ mapView: MKMapView,
didAdd views: [MKAnnotationView]){
for view in views {
if view.annotation is MKUserLocation {
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.handleStuff)))
}
}
}

Related

Detecting MapView finished changing region

I have a MKMapView that has annotations. My goal is to hide the annotation, if one is selected, when the map finished scrolling.
When an annotation is called I assign the annotation into a variable to keep track of it.
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
lastSelectedAnnotation = view.annotation
}
I know of:
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool){ }
However, I cannot figure out (beginner here), how to detect that the map finished changing its region so I can call my function:
func hideSelectedAnnotation(_ mapView: MKMapView) {
DispatchQueue.main.async {
mapView.deselectAnnotation(self.lastSelectedAnnotation, animated: true)
self.lastSelectedAnnotation = nil
}
}
I hide the annotation also when an accessory button is tapped:
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl){
hideSelectedAnnotation(mapView)}
I have tried saving the coordinate of the region, and comparing them to the map but the map does not neccessarily center the annotation. I could also start a timer and when regionDidChangeAnimated is no longer called hide the annotation. But that seams like butchering it.
Thanks for any help!
I think you already figured it out...
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool){
// Call your function here
}
Should fire every time the map view region changes (unless the change was inflicted by the user's finger)
----- EDIT -----
Unfortunately, you have to detect user input using a UIPanGestureRecognizer.
I have used, with success, A UIPanGestureRecognizer like the following:
lazy var mapPanGestureRecognizer: UIPanGestureRecognizer = {
let gr = UIPanGestureRecognizer(target: self, action: #selector(draggedMap))
gr.delegate = self
return gr
}()
You will also have to add the UIPanGestureRecognizer to the map with
yourMap.addGestureRecognizer(mapPanGestureRecognizer)
You can then manage what happens in the #selector function by checking the state of the gesture, like so
#objc func draggedMap(panGestureRecognizer: UIPanGestureRecognizer) {
// Check to see the state of the passed panGestureRocognizer
if panGestureRecognizer.state == UIGestureRecognizer.State.began {
// Do something
}
}
The state is what allows you to determine if the user ended a gesture, is in the middle of a gesture, or began a gesture.
List of possible states

How to change markerTintColor in MapKit without changing default location pin in Swift?

I have MKMarkerAnnotationView to change color of pins on my map.
func mapView(_ MapView:MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?{
let view = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: "pin")
view.markerTintColor = .blue
return view
}
But, when I start my app, marker of my defoult location changes to.
How can I change pin without changing this marker?
Code to view location is also simple
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
self.MapView.showsUserLocation = true
}
Thanks for answer! :)
You could check if the annotation is the user location like this:
func mapView(_ MapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let view = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: "pin")
view.markerTintColor = .blue
return view
}
In your method, check to see if the annotation object is an instance of MKUserLocation. If it is, return nil to keep the standard user location annotation view.
(The Docs for mapView(_:viewFor:) explain this.)

Add delegate to CalloutView

I am currently using the MapBox swift library and I am trying to add a delegate to the callout view.
I am trying to do it like this :
func mapView(_ mapView: MGLMapView, calloutViewFor annotation: MGLAnnotation) -> MGLCalloutView? {
let callout = TabletMapSearchCalloutView(representedObject: annotation, mapView: mapView)
callout.delegate = self
return callout
}
But it seems that there is an internal worker that runs in the library that sets the delegate after this method to the MGLMapView.
So my question is, how do I go about adding a delegate to the callout so that I can access the tapped event?
So it seems the MGLMapViewDelegate has the method that I was looking for
func mapView(_ mapView: MGLMapView, tapOnCalloutFor annotation: MGLAnnotation)

MapBox in Swift - Allowing a marker's annotation to have a button that links to a View

I have set up a simple app with a tabbed map view (map on tab 1) that reads info from a json file on a server (point info is stored in MySQL) with SwiftyJSON and Alamofire. The points are loaded into the map. What I would like to do is add a button to the annotation, which outlets to a different view tab and passes along the point's ID.
I have not tried anything yet as I have no idea where to get started and the documentation doesn't mention anything similar.
How does one go about adding an outlet to a map point annotation?
When you tap your pin the callout appears with a title and/or a subtitle. You need to add left and right callout accessory views to this callout. You do this by conforming to the MGLMapViewDelegate and implementing the following methods:
func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
return true
}
func mapView(_ mapView: MGLMapView, leftCalloutAccessoryViewFor annotation: MGLAnnotation) -> UIView? {
...your code here...
let deleteButton = UIButton(type: .custom)
deleteButton.tag = 100
}
func mapView(_ mapView: MGLMapView, rightCalloutAccessoryViewFor annotation: MGLAnnotation) -> UIView? {
...your code here...
let infoButton = UIButton(type: .custom)
infoButton.tag = 101
}
func mapView(_ mapView: MGLMapView, annotation: MGLAnnotation, calloutAccessoryControlTapped control: UIControl) {
...your code here...
switch control.tag {
case 100:
// do some delete stuff
case 101:
// do some info stuff
default:
break
}
The MapBox example showing actual usage is here:
MapBox example. This example doesn't segue but you would just trigger a segue with the button tap instead of the UIAlert.
For future reference:
func mapView(_ mapView: MGLMapView, annotation: MGLAnnotation, calloutAccessoryControlTapped control: UIControl) {
// Hide the callout view.
// mapView.deselectAnnotation(annotation, animated: true)
performSegue(withIdentifier: "toDetail", sender: view)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
print("Seque toDetail")
// do stuff
}

How to add iOS 10 default annotation/pin?

I have a MapView in my app. And user can add an annotaion/pin to that MapView. I works fine but I would like to know if it is possible to add new annotation design.
This is the new pin:
This is what my map shows:
This is my annotation code:
let annotaion = MKPointAnnotation()
this line adds my annotation to map:
self.myMap.addAnnotation(self.annotaion)
Thank you.
I believe #0ndre_ was looking for the default image, not to bring in his own custom image. The answer by #Franco_Meloni was incomplete. Here is how I got it to work.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let pin = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: nil)
pin.canShowCallout = true
let button = UIButton(type: .detailDisclosure)
pin.rightCalloutAccessoryView = button
if annotation.isEqual(mapView.userLocation) {
return nil
}
return pin
}
The key is using MKMarkerAnnotationView to get the bigger marker. If you use MKPinAnnotationView you will see the smaller one appear.
You should implement
mapView(_ mapView: MKMapView,
viewFor annotation: MKAnnotation) -> MKAnnotationView?
from MKMapViewDelegate (https://developer.apple.com/reference/mapkit/mkmapviewdelegate/1452045-mapview)
Implementation example:
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let view = MKAnnotationView()
view.image = UIImage(named: "pin")
return view
}

Resources