2014-06-12 11 views
5

Ho una sottoclasse personalizzata di che visualizza una chiamata personalizzata. Voglio gestire gli eventi di tocco all'interno di quell'annotazione.Prevenire la modifica della selezione di MKMapView (in modo pulito)

Ho una soluzione di lavoro (sotto) ma non mi sembra giusto. Ho una regola pratica che ogni volta che uso performSelector: .. withDelay: sto combattendo il sistema piuttosto che lavorare con esso.

Qualcuno ha una soluzione buona e pulita per la gestione di eventi aggressivi di MKMapView e la gestione della selezione di annotazioni?

mia soluzione attuale:

(Tutto il codice dalla mia annotazione di classe selezione)

faccio la mia hit testing (senza che questo mio gesto riconoscitori non vengono attivati ​​come la mappa consuma gli eventi :

- (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; 
} 

Nota che anche io spengo le selezioni in modo che nella mia sovrascritti setSelected posso ignorare la disattivazione

0.
- (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]; 
    } 


} 

E 'la linea commentata che non mi piace ma è anche piuttosto pelosa alla fine del fuoco ritardato theta. Devo risalire la catena superview per arrivare alla mapView in modo che possa convincerlo che la selezione è ancora in vigore.

// 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; 

} 

con

-(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; 
} 

Tutto questo sembra funzionare senza e lato negativo (come sfarfallio che ho visto da altre soluzioni. E 'relativamente semplice, ma non mi sembra giusto.

Chiunque avere una soluzione migliore?

risposta

1

Non penso che sia necessario scimmiottare il tracciamento della selezione della mappa. Se sto interpretando correttamente quello che vuoi, dovresti essere in grado di ometterlo con solo la sostituzione hitTest:withEvent: e canShowCallout impostato su NO. In setSelected: eseguire di conseguenza l'animazione di comparsa/scomparsa del callout. Dovresti anche eseguire l'override di setHighlighted: e regolare la visualizzazione del callout personalizzato se visibile.