MKAnnotationView和点击检测

时间:2013-06-19 20:41:22

标签: ios objective-c mkmapview mkannotation mkannotationview

我有MKMapView。我只需点击一下即可添加UITapGestureRecognizer

我现在想在地图中添加MKAnnotationView。我可以点击注释和mapView:mapView didSelectAnnotationView:view fires(我将添加其他逻辑以显示UIView)。

问题是,当我点按注释时,MKMapView点击手势也会触发。

我可以设置它,如果我点击注释,它只会响应吗?

5 个答案:

答案 0 :(得分:5)

可能有一个更好更清洁的解决方案,但一种方法是利用点击手势识别选择器中的hitTest:withEvent:,例如

假设您已在自_mapView

中添加了点按手势识别器
- (void)tapped:(UITapGestureRecognizer *)g
{
    CGPoint p = [g locationInView:_mapView];
    UIView *v = [_mapView hitTest:p withEvent:nil];

    if (v ==  subviewOfKindOfClass(_mapView, @"MKAnnotationContainerView"))
        NSLog(@"tap on the map"); //put your action here
}

// depth-first search
UIView *subviewOfKindOfClass(UIView *view, NSString *className)
{
    static UIView *resultView = nil;

    if ([view isKindOfClass:NSClassFromString(className)])
        return view;

    for (UIView *subv in [view subviews]) {
        if ((resultView = subviewOfKindOfClass(subv, className)) break;
    }
    return resultView;
}

它可能并未覆盖所有边缘情况,但它似乎对我来说非常好。

更新(iOS> = 6.0)

最后,我找到了另一种解决方案,其缺点是仅对 iOS> = 6.0 有效:事实上,此解决方案利用了添加到{的新-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer以这种方式{1}}

UIView

即,从iOS 6开始,在手势识别器应忽略的每个视图中覆盖- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { // overrides the default value (YES) to have gestureRecognizer ignore the view return NO; } 方法就足够了。

答案 1 :(得分:4)

您的解决方案应该在您的代理上使用- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch方法。

在此方法中,您可以检查是否在其中一个注释上进行了触摸,如果是,则return NO,以便gestureRecognizer未被激活。

目标-C:

- (NSArray*)getTappedAnnotations:(UITouch*)touch
{
    NSMutableArray* tappedAnnotations = [NSMutableArray array];
    for(id<MKAnnotation> annotation in self.mapView.annotations) {
        MKAnnotationView* view = [self.mapView viewForAnnotation:annotation];
        CGPoint location = [touch locationInView:view];
        if(CGRectContainsPoint(view.bounds, location)) {
            [tappedAnnotations addObject:view];
        }
    }
    return tappedAnnotations;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    return [self getTappedAnnotations:touch].count > 0;
}

夫特:

private func getTappedAnnotations(touch touch: UITouch) -> [MKAnnotationView] {
    var tappedAnnotations: [MKAnnotationView] = []
    for annotation in self.mapView.annotations {
        if let annotationView: MKAnnotationView = self.mapView.viewForAnnotation(annotation) {
            let annotationPoint = touch.locationInView(annotationView)
            if CGRectContainsPoint(annotationView.bounds, annotationPoint) {
                tappedAnnotations.append(annotationView)
            }
        }
    }
    return tappedAnnotations
}

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    return self.getTappedAnnotations(touch: touch).count > 0
}

答案 2 :(得分:1)

为什么不在viewForAnnotation中添加UITapGestureRecognazer,使用注释的reuseIdentifier来识别它是哪个注释,而在tapGestureRecognizer操作方法中,您可以访问该标识符。

-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
    MKAnnotationView *ann = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:@"some id"];

    if (ann) {
        return ann;
    }

    ann = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"some id"];
    ann.enabled = YES;

    UITapGestureRecognizer *pinTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(pinTapped:)];
    [ann addGestureRecognizer:pinTap];
}

-(IBAction)pinTapped:(UITapGestureRecognizer *)sender {
    MKAnnotationView *pin = (MKPinAnnotationView *)sender.view;
    NSLog(@"Pin with id %@ tapped", pin.reuseIdentifier);
}

答案 3 :(得分:0)

我不确定你为什么在你的地图视图上会有UITapGestureRecognizer,说这是明文暗示它会让你的地图有一些多点触控功能。

我建议您查看并使用cancelsTouchesInView的{​​{1}}属性(请参阅documentation)。我认为这可以解决你的问题。请务必查看文档。

答案 4 :(得分:0)

如果仅在手势委托中测试touch.view的超级视图,就会容易得多:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    var tv = touch.view
    while let view = tv, !(view is MKAnnotationView) {
        tv = view.superview
    }
    return tv == nil
}