2013-09-30 12 views
9

Per diversi anni ho operato partendo dal presupposto che se una superview e la sua sottoview avevano entrambi riconoscimenti di gesti, la sottoview avrebbe ricevuto i primi tocchi e annullato il gesto della superview. Fino a iOS 7 questa ipotesi non mi ha mai deluso, permettendomi di aggiungere gesti alle sottoview confidando che i gesti della superview non interferirebbero. Ma in iOS 7, la superview riceverà casualmente i tocchi e annulla i gesti della subview. Questo accade un po 'di rado, il che ha reso difficile individuare il problema.Il gesto di superview dovrebbe annullare il gesto di subview in iOS 7?

Ho riscontrato questo problema per la prima volta come pulsanti che non è stato possibile utilizzare utilizzando UITapGestureRecognizer ... di nuovo, molto raramente. Di solito i pulsanti funzionavano finché non lo facevano. Ti ha fatto mettere in discussione la tua sanità mentale. Così ho lanciato il mio TapGestureRecognizer e ho scoperto che i rubinetti delle superview stavano cancellando i rubinetti della loro sottoview occasionalmente. Non è mai stato fatto in nessuna versione precedente di iOS, ma mi chiedo se questo comportamento non sia mai stato promesso.

Ho pensato che il gesto della subview avrebbe dovuto annullare il suo gesto di superview (se non diversamente specificato da un delegato). È sbagliato o è un bug?

Nota: Non sto chiedendo come gestire la situazione. Sto chiedendo se qualcuno sa se la mia ipotesi è sbagliata. Sto già riorganizzando le visualizzazioni, aggiungendo/rimuovendo dinamicamente i gesti e creando implementazioni piuttosto complesse di gestureRecognizer:shouldReceiveTouch: per rimediare alla situazione. Non è divertente, ma posso aggirare il problema.

risposta

8

Dopo molte ricerche ho trovato una discussione sulle bacheche di Apple con altri utenti che hanno questo problema: Issues with UITapGestureRecognizer (account sviluppatore richiesto). Sono andato avanti e ho presentato una segnalazione di bug: 15331126 (qualcuno sa più come collegarsi alle segnalazioni di bug?). Nel frattempo, ho implementato questa soluzione alternativa. Finora sembra che funzioni, ma dal momento che il bug è così raro, forse non l'ho ancora attivato. Lo sto rilasciando ai miei utenti beta e se non ricevo lamentele da loro (che si sono lamentati) presumo che questo risolva il problema.

UPDATE: Questa soluzione ha risolto il problema. Dopo settimane di utilizzo da parte di decine di utenti non ho avuto un singolo problema con i gesti.

La maggior parte dei miei gesti sono personalizzati. Li ho alterato per essere delegati di se stessi e attuate:

- (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ 
    if (gestureRecognizer == self){ 
     if ([otherGestureRecognizer isMemberOfClass:self.class]){ 
      if ([self isGestureRecognizerInSuperviewHierarchy:otherGestureRecognizer]){ 
       return YES; 
      } else if ([self isGestureRecognizerInSiblings:otherGestureRecognizer]){ 
       return YES; 
      } 
     } 
    } 
    return NO; 
} 

Nota che i miei gestureRecognizers personalizzati implementare il protocollo UIGestureRecognizerDelegate ora (pubblicamente, per motivi si vedrà più avanti). Ho anche aggiunto un paio di categorie per UIGestureRecognizer (usato nel codice qui sopra):

- (BOOL) isGestureRecognizerInSiblings:(UIGestureRecognizer *)recognizer{ 
    UIView *superview = self.view.superview; 
    NSUInteger index = [superview.subviews indexOfObject:self.view]; 
    if (index != NSNotFound){ 
    for (int i = 0; i < index; i++){ 
      UIView *sibling = superview.subviews[i]; 
      for (UIGestureRecognizer *viewRecognizer in sibling.gestureRecognizers){ 
       if (recognizer == viewRecognizer){ 
        return YES; 
       } 
      } 
     } 
    } 
    return NO; 
} 
- (BOOL) isGestureRecognizerInSuperviewHierarchy:(UIGestureRecognizer *)recognizer{ 
    if (!recognizer) return NO; 
    if (!self.view) return NO; 
    //Check siblings 
    UIView *superview = self.view; 
    while (YES) { 
     superview = superview.superview; 
     if (!superview) return NO; 
     for (UIGestureRecognizer *viewRecognizer in superview.gestureRecognizers){ 
      if (recognizer == viewRecognizer){ 
       return YES; 
      } 
     } 
    } 
} 

io non sono del tutto sicuro che ho bisogno di verificare la presenza di fratelli, come ho visto solo il problema si verifica con i gesti Superview. Tuttavia, non volevo cogliere questa occasione. Nota che controllo solo i fratelli "sotto" quello attuale perché non voglio cancellare i gesti di visualizzazione "sopra" la vista corrente.

ho dovuto aggiungere implementazioni per per quelle classi che si pongono come delegati dei riconoscitori personalizzati, ma praticamente solo richiamo alla gestureRecognizer:

- (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ 
    if ([gestureRecognizer respondsToSelector:@selector(gestureRecognizer:shouldBeRequiredToFailByGestureRecognizer:)]){ 
     return [(id <UIGestureRecognizerDelegate>)gestureRecognizer gestureRecognizer:gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:otherGestureRecognizer]; 
    } 
    return NO; 
} 

Spero che questo aiuti chiunque altro avere il problema.

+0

Avete ricevuto qualche feedback su questo dalla nave madre? Sarebbe più carino avere un mezzo/protocollo più chiaro per stabilire l'ordine. (E grazie per il tuo post) –

+0

No, non proprio. Il radar che ho presentato è stato infine rimosso come "comportamento previsto". Tuttavia, ho notato nelle versioni più recenti di iOS che non ho visto il problema apparire così ho il sospetto che qualcosa fosse stato risolto internamente. –

+0

Roba buona! Ora mi trovo a dare una lunga prefazione su come il bug che sto descrivendo non potrebbe mai essere considerato ragionevole da una persona sana di mente, e cercando di chiarire il punto che il previsto non è lo stesso di quello corretto. Ho anche avuto bug tornare come previsto, e in seguito risolto - non sono sicuro di come ciò accada. Ancora una volta nella breccia! ;-) –