Identify Mkpointannotation in Mapview

How to identify if MKPointAnnotation has been pressed in Swift?

mapView:didSelect: is a MKMapViewDelegate method. If you do not set mapView.delegate = self on your ViewController this function will never get triggered.

Typically it would get set in ViewDidLoad. before performing any other operations with the mapView. Changing your ViewDidLoad to look like

override func viewDidLoad() {
super.viewDidLoad()

self.mapView.delegate = self
displayCordinates()
}

should fix your issue. For more information on the protocol/delegate design pattern all over the apple frameworks, I suggest this swift article from the Swift Programming Guide.

More specifically to your case, check out all the other functionality/control you can bring with your implementation of MKMapView on your ViewController by checkout out the apple docs on MKMapViewDelegate. This will cover things like monitoring when the map finishes loading, when it fails, when the user's location is updated, and more things you may want to increase the functionality of your app and provide a great user experience.

How to call a function or tell if a MKPointAnnotation is clicked on a MKMapView SwiftUI

Assuming that you're wrapping your MKMapView inside a UIViewRepresentable struct, add a coordinator with the MKMapViewDelegate protocol to listen for changes on your map:

//Inside your UIViewRepresentable struct
func makeCoordinator() -> Coordinator {
Coordinator()
}

class Coordinator: NSObject, MKMapViewDelegate {
//Delegate function to listen for annotation selection on your map
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
if let annotation = view.annotation {
//Process your annotation here
}
}
}

There are a couple of tutorials out there on how to include an MKMapView in SwiftUI and use delegation to access the MKMapViewDelegate functions through UIViewRepresentable and coordinators.

Following along my suggestion, your previous code would look like so:

struct MapKitView: UIViewRepresentable {

typealias Context = UIViewRepresentableContext<MapKitView>

func makeUIView(context: Context) -> MKMapView {
let map = MKMapView()
map.delegate = context.coordinator
let annotation = MKPointAnnotation()

annotation.coordinate = donator.coordinates
annotation.title = donator.name
annotation.subtitle = donator.car
map.addAnnotation(annotation)
return map
}

//Coordinator code
func makeCoordinator() -> Coordinator { ... }
}

How can I detect which annotation was selected in MapView

For that you can use selected Annotation from didSelectAnnotationView, then store that annotation to instance variable and after that used annotation in your Button action method.

var selectedAnnotation: MKPointAnnotation?

func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
self.selectedAnnotation = view.annotation as? MKPointAnnotation
}

func info(sender: UIButton) {
print(selectedAnnotation?.coordinate)
}

Edit: As of you have custom MKAnnotation class you need to use that.

var selectedAnnotation: Islands?

func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
self.selectedAnnotation = view.annotation as? Islands
}

Get MKPointAnnotation title

In the custom rightButtonTapped method, an easy and reliable way to get a reference to the annotation that was tapped is to use the map view's selectedAnnotations array:

func rightButtonTapped(sender: AnyObject) {
if self.mapView.selectedAnnotations?.count == 0 {
//no annotation selected
return;
}

if let ann = self.mapView.selectedAnnotations[0] as? MKAnnotation {
println("\(ann.title!)")
}
}

(Even though selectedAnnotations is an array, the map view only allows one annotation to be "selected" at a time so the currently selected annotation is always at index 0.)


However, a better way than using a custom button method is to use the map view's calloutAccessoryControlTapped delegate method. The delegate method passes you a reference to the annotation view that was tapped from which you can easily get the underlying annotation.

To use the delegate method, remove the addTarget line for your custom method:

//Do NOT call addTarget if you want to use the calloutAccessoryControlTapped
//delegate method instead of a custom button method.
//rightButton.addTarget(self, action: "rightButtonTapped:", forControlEvents: UIControlEvents.TouchUpInside)

and then implement the delegate method instead of your custom button method:

func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!) {
println("\(view.annotation.title!)")
}

How to identify when a annotation is pressed which one it is

As I can see, you've already created a class subclassing a MKPointAnnotation.

This is simple, you just create a variable with a name and type.

class CustomPointAnnotation: MKPointAnnotation {
var tag: Int!
}

Then in your code, set the variable.

var pin = CustomPointAnnotation()
pin.coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
pin.title = "Bus Stop"
pin.subtitle = "City Stand D"
pin.imageName = "pin"
pin.tag = index

mapView.addAnnotation(pin)

Then to access the variable when you click on the annotation. Simply do it here.

func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {

if let annotation = view.annotation as? CustomPointAnnotation {
print(annotation.tag!)
}

}

There you go.

If you have any issues shoot me a comment.

MKMapView MKPointAnnotation tap event

There are two ways of detecting user interaction with your annotation view. The common technique is to define a callout (that standard little popover bubble that you see when you tap on a pin in a typical maps app) for your MKAnnotationView. And you create the annotation view for your annotation in the standard viewForAnnotation method:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;

MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"loc"];
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];

return annotationView;
}

By doing this, you get a callout, but you're adding an right accessory, which is, in my example above, a disclosure indicator. That way, they tap on your annotation view (in my example above, a pin on the map), they see the callout, and when they tap on that callout's right accessory (the little disclosure indicator in this example), your calloutAccessoryControlTapped is called (in my example below, performing a segue to some detail view controller):

- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
[self performSegueWithIdentifier:@"DetailsIphone" sender:view];
}

That's a very typical user experience on the small iPhone screen.

But, if you don't like that UX and you don't want the standard callout, but rather you want something else to happen, you can define your MKAnnotationView so that a callout is not shown, but instead you intercept it and do something else (for example, on iPad maps apps, you might show some more sophisticated popover rather than the standard callout). For example, you could have your MKAnnotationView not show a callout:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;

MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"loc"];
annotationView.canShowCallout = NO;

return annotationView;
}

But you can then manually handle didSelectAnnotationView to detect when a user tapped on your MKAnnotationView, in this example showing a popover:

- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
[mapView deselectAnnotation:view.annotation animated:YES];

DetailsViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"DetailsPopover"];
controller.annotation = view.annotation;
self.popover = [[UIPopoverController alloc] initWithContentViewController:controller];
self.popover.delegate = self;
[self.popover presentPopoverFromRect:view.frame
inView:view.superview
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}

I include some screen snapshots for the user interface yielded by the above code in my answer here.



Related Topics



Leave a reply



Submit