Pergunta

I have a UITapGestureRecognizer that will hide and show a toolbar over my MKMap when the user taps the Map - simple.

However, when the user taps on an MKMapAnnotation, I do not want the map to respond to a tap in the normal way (above). Additionally, when the user taps elsewhere on the map to de-select an MKAnnotation callout, I also don't want the toolbar to respond. So, the toolbar should only respond when there are no MKAnnotations currently in selected state. Nor should it respond when the user clicks on an annotation directly.

So far, I have being trying the following action that reacts to the tap gesture on the map - however the Annotation View is never detected (the first if statement) and also, the annotation view is also launched regardless of this method.

 -(void)mapViewTapped:(UITapGestureRecognizer *)tgr
{
    CGPoint p = [tgr locationInView:self.mapView];

    UIView *v = [self.mapView hitTest:p withEvent:nil];

    id<MKAnnotation> ann = nil;

    if ([v isKindOfClass:[MKAnnotationView class]])<---- THIS CONDITION IS NEVER MET BUT ANNOTATIONS ARE SELECTED ANYWAY
    {
        //annotation view was tapped, select it…
        ann = ((AircraftAnnotationView *)v).annotation;
        [self.mapView selectAnnotation:ann animated:YES];
    }
    else
    {

        //annotation view was not tapped, deselect if some ann is selected...
        if (self.mapView.selectedAnnotations.count != 0)
        {
            ann = [self.mapView.selectedAnnotations objectAtIndex:0];
            [self.mapView deselectAnnotation:ann animated:YES];
        }

        // If no annotation view is selected currently then assume control of
        // the navigation bar.
        else{

            [self showToolBar:self.navigationController.toolbar.hidden];
        }
    }
}

I need to control the launch of the annotation call out programmatically and detect when the tap event has hit an annotation in order to achieve this.

Any help would be appreciated.

Foi útil?

Solução

I think you will find the following links very useful:

http://blog.asynchrony.com/2010/09/building-custom-map-annotation-callouts-part-2/

How do I make a MKAnnotationView touch sensitive?

The first link discusses (among other things) how to prevent the propagation of touches to the annotations so that they selectively respond, and the second one how to detect the touches.

Outras dicas

I think that because MKMapAnnotationView are on top of MKMapView, they will get the touch event and respond to it (be selected) so I don't think you need to select your annotation manually.

Then, if you have a look at Advanced Gesture Recognizer WWDC 2010 video, you will see that your MKMapView will receive tap event anyway, even if it's below the annotation view. That's probably why your -(void)mapViewTapped:(UITapGestureRecognizer *)tgr method get called.

Apart from that, I can't see why your if ([v isKindOfClass:[MKAnnotationView class]]) is never true. I do the exact same thing in my code and it works fine!

Finally, to answer your last question, if you don't want to do anything when the user is just trying to close the callout, you could keep track of a custom isCalloutOpen boolean value like this:

- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
    //some code
    _isCalloutOpen = YES;
}

- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view {
    // delay the reset because didDeselectAnnotationView could (and is often) called before your gesture recgnizer handler method get called.
    [self performSelector:@selector(resetCalloutOpenState) withObject:Nil afterDelay:0.1];
}

- (void)resetCalloutOpenState {
    _isCalloutOpen = NO;
}

- (void)mapViewTapped:(UITapGestureRecognizer *)tgr {
    if (_isCalloutOpen) {
        return;
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top