Ios 防止MKMapView更改选择(干净)

Ios 防止MKMapView更改选择(干净),ios,objective-c,mkmapview,uigesturerecognizer,uievent,Ios,Objective C,Mkmapview,Uigesturerecognizer,Uievent,我有一个自定义子类MKPinAnnotationView,它显示一个自定义调用。我想处理注释中的触摸事件 我有一个可行的解决方案(如下),但感觉不太对劲。我有一个经验法则,每当我使用performSelector:。。延迟:我正在与系统对抗,而不是与它合作 对于MKMapView的攻击性事件处理和注释选择处理,有人有好的、干净的解决方法吗 我当前的解决方案: (我的注释选择类中的所有代码) 我自己做命中测试(如果没有此功能,我的手势识别器不会启动,因为地图视图会消耗事件: - (UIView*)

我有一个自定义子类
MKPinAnnotationView
,它显示一个自定义调用。我想处理注释中的触摸事件

我有一个可行的解决方案(如下),但感觉不太对劲。我有一个经验法则,每当我使用
performSelector:。。延迟:
我正在与系统对抗,而不是与它合作

对于MKMapView的攻击性事件处理和注释选择处理,有人有好的、干净的解决方法吗

我当前的解决方案:

(我的注释选择类中的所有代码)

我自己做命中测试(如果没有此功能,我的手势识别器不会启动,因为地图视图会消耗事件:

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event; {
    // To enable our gesture recogniser to fire. we have to hit test and return the correct view for events inside the callout.

    UIView* hitView = nil;

    if (self.selected) {
        // check if we tpped inside the custom view
        if (CGRectContainsPoint(self.customView.frame, point))
            hitView = self.customView;
    }

    if(hitView) {
        // If we are performing a gesture recogniser (and hence want to consume the action)
        // we need to turn off selections for the annotation temporarily
        // the are re-enabled in the gesture recogniser.
        self.selectionEnabled = NO;

        // *1* The re-enable selection a moment later
        [self performSelector:@selector(enableAnnotationSelection) withObject:nil afterDelay:kAnnotationSelectionDelay];

    } else {
        // We didn't hit test so pass up the chain.
        hitView = [super hitTest:point withEvent:event];
    }

    return hitView;
}
请注意,我还关闭了选择,以便在覆盖的
setSelected
中可以忽略取消选择

- (void)setSelected:(BOOL)selected animated:(BOOL)animated; {
    // If we have hit tested positive for one of our views with a gesture recogniser,  temporarily 
    // disable selections through _selectionEnabled
    if(!_selectionEnabled){
        // Note that from here one, we are out of sync with the enclosing map view
        // we're just displaying out callout even though it thinks we've been deselected
        return;
    }

    if(selected) {
        // deleted code to set up view here
        [self addSubview:_customView];

        _mainTapGestureRecogniser = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(calloutTapped:)];
        [_customView addGestureRecognizer: _mainTapGestureRecogniser];

    } else {
        self.selected = NO;
        [_customView removeFromSuperview];
    }


}
这是我不喜欢的评论1行,但在θ延迟射击结束时它也很毛茸茸的。我必须沿着superview链返回到mapView,这样我才能说服它选择仍然存在

// Locate the mapview so that we can ensure it has the correct annotation selection state after we have ignored selections.
- (void)enableAnnotationSelection {
    // This reenables the seelction state and resets the parent map view's idea of the
    // correct selection i.e. us.
    MKMapView* map = [self findMapView];
    [map selectAnnotation:self.annotation animated:NO];
    _selectionEnabled = YES;

}

这一切似乎都没有缺点(就像我在其他解决方案中看到的闪烁一样)。它相对简单,但感觉不对劲


有谁有更好的解决方案吗?

我认为您不需要对地图视图的选择跟踪进行蒙混过关。如果我正确地解释了您想要的内容,您应该能够通过
hitTest:withEvent:
覆盖和
canShowCallout
设置为
NO
。在
setSelected:
中执行您的操作调用外观/消失动画。您还应覆盖
设置突出显示:
,并调整自定义调用的显示(如果可见)

-(MKMapView*)findMapView; {
    UIView* view = [self superview];
    while(!_mapView) {
        if([view isKindOfClass:[MKMapView class]]) {
            _mapView = (MKMapView*)view;
        } else if ([view isKindOfClass:[UIWindow class]]){
            return nil;
        } else{
            view = [view superview];
            if(!view)
                return nil;
        }
    }

    return _mapView;
}