2012-07-16 3 views
5

Sto visualizzando un documento in una UIWebView. Voglio posizionare un hotspot sul documento per attivare un'azione quando viene toccato, ma voglio anche mantenere il comportamento di UIWebView predefinito dello zoom automatico del documento quando viene toccato due volte. Non riesco a capire come rispondere ai single-tap mentre permetto a UIWebView di rispondere ai doppi tocchi.Come rispondere solo a un gesto a tocco singolo mentre si lascia che gli oggetti alle spalle rispondano ai doppi tocchi?

Prima ho impostato l'hotspot come un UIButton trasparente con un'azione, ma toccando due volte l'hotspot, l'azione dell'hotspot veniva richiamata due volte. Così ho tolto l'azione dal bottone e attaccato un gesto single-tap, invece:

UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapAction:)]; 
singleTap.numberOfTapsRequired = 1; 
singleTap.delegate = self; 
[self.hotspot addGestureRecognizer:singleTap]; 
[singleTap release]; 

questo funziona lo stesso del normale azione del pulsante. Ma poi ho creato un gesto doppio tocco, e configurato per bloccare il gesto single-tap con requireGestureRecognizerToFail:

UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(zoomWebView:)]; 
doubleTap.numberOfTapsRequired = 2; 
doubleTap.delegate = self; 
[self.hotspot addGestureRecognizer:doubleTap]; 
[doubleTap release]; 

UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapAction:)]; 
singleTap.numberOfTapsRequired = 1; 
[singleTap requireGestureRecognizerToFail:doubleTap]; 
singleTap.delegate = self; 
[self.hotspot addGestureRecognizer:singleTap]; 
[singleTap release]; 

- (void)zoomWebView:(UITapGestureRecognizer *)gesture { 
    NSLog(@"double tap"); 
} 

Con questa impostazione, un single-tap sul hotspot chiama singleTapAction e un doppio-tap sulla hotspot chiama zoomWebView (un metodo personalizzato). Ciò è positivo perché singleTapAction non viene più chiamato due volte, ma è negativo perché UIWebView non risponde più al doppio tocco.

Ho tentato di inoltrare l'evento di doppio tocco dal mio gesto doubleTap a UIWebView sottoclassando UITapGestureRecognizer, ignorando i touchBegan e toccando i metodi Ended e inviando i loro argomenti ai metodi corrispondenti di UIWebView. Quando l'ho fatto, ho potuto vedere che la mia sottoclasse stava ricevendo gli eventi, ma UIWebView non ha risposto agli eventi inoltrati. Questo è prevedibile perché il Event Handling Guide for iOS dice che possiamo solo inoltrare eventi a sottoclassi personalizzate di UIView, non a oggetti framework UIKit.

C'è un modo per impedire al mio gesto di tocco singolo di rispondere a due volte che non devia gli eventi di doppio tocco? Questo sembra un requisito di base, ma non riesco a vedere un modo semplice per farlo. Ho letto e sperimentato con UIGestureRecognizer's touch delivery properties, ma nessuna combinazione di valori ha impedito al gesto a tocco singolo di consumare il gesto del doppio tocco.

A proposito, la relazione tra l'hotspot e UIWebView nella mia gerarchia di vista è quella di "cugini" - sono sottoview di due visualizzazioni di pari livello. Se aggiungo il riconoscimento dei gesti alla vista hotspot, la vista Web o la loro vista "nonno", ottengo gli stessi risultati.

+0

non sono sicuro di questo (e quindi essendo un commento), ma non si può aggiungere un solo gesto rubinetto per l'UIWebView? –

+0

@DeanPucsek Lo stavo facendo da un po 'e ha funzionato durante la visualizzazione di documenti PDF. Ma se il contenuto mostrato in UIWebView è HTML o JPG, UIWebView acquisisce il single-tap per le proprie azioni e UIGestureRecognizer non riceve l'evento. Sarebbe più comodo gestirlo con una visualizzazione hotspot, ma potrei tornare a questo approccio se potessi farlo funzionare con tutti i tipi di contenuto di UIWebView. – arlomedia

risposta

15

Va bene, ho trovato una soluzione in due parti:

1) ho dovuto aggiungere i miei gesti ad una vista genitore del UIWebView. Gli eventi senza corrispondenza non viaggiano attraverso oggetti sovrapposti in una vista da un livello all'altro come immaginavo. Invece, viaggiano attraverso la gerarchia dei punti di vista da bambino a genitore.Quindi, fino a quando aggiungevo il mio gesto di doppio tocco a una visualizzazione di pari livello o "cugina" di UIWebView, non si sarebbe mai passati alla visualizzazione web. Ciò significa che non posso usare pulsanti o viste disposti in Interface Builder per determinare più aree di hotspot. Invece, devo reindirizzare tutti gli eventi single-tap a un metodo e quindi guardare le posizioni touch per determinare quale azione attivare.

2) Ho dovuto aggiungere il gestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizer: metodo al mio controller di visualizzazione (il delegato dei miei gesti) e return YES. Ciò consente al mio gesto di tocco singolo di rispondere anche quando visualizzo contenuto HTML, testo o immagine in UIWebView, che implementa il proprio gesto per questi tipi di contenuto. Ho imparato questa parte da this answer.

Con queste modifiche, capisco la gerarchia di eventi da:

  • Single-tap vista web: il mio gesto single-tap sulla vista padre della vista web risponde; il gesto a tocco singolo della visualizzazione Web risponde anche, se applicabile, perché i gesti simultanei sono abilitati.

  • Visualizzazione web a doppio tocco: il mio gesto a doppio tocco sulla vista principale della visualizzazione Web risponde (ma non esegue nulla); il mio gesto a tocco singolo non risponde perché è configurato per rispondere solo se il doppio tocco fallisce; l'evento di doppio tocco della vista Web risponde anche perché fa parte della gerarchia della vista (sembra che la funzionalità di doppio tocco della visualizzazione Web non usi un gesto perché altrimenti avrebbe avuto la precedenza sul mio stesso gesto nella mia configurazione originale)

Con questa spiegazione di mezzo, ecco qualche codice di lavoro:

- (void)viewDidLoad { 
    UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTapWebView:)]; 
    doubleTap.numberOfTapsRequired = 2; 
    doubleTap.delegate = self; 
    [self.webViewParent addGestureRecognizer:doubleTap]; 
    [doubleTap release]; 

    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapWebView:)]; 
    singleTap.numberOfTapsRequired = 1; 
    [singleTap requireGestureRecognizerToFail:doubleTap]; 
    singleTap.delegate = self; 
    [self.webViewParent addGestureRecognizer:singleTap]; 
    [singleTap release]; 
} 

- (void)doubleTapWebView:(UITapGestureRecognizer *)gesture { 
    NSLog(@"double-tap"); 
    // nothing to do here 
} 

- (void)singleTapWebView:(UITapGestureRecognizer *)gesture { 
    NSLog(@"single-tap"); 
    CGPoint touchLocation = [gesture locationInView:self.webViewParent]; 
    float x = touchLocation.x; 
    float y = touchLocation.y; 
    CGRect frame = self.webViewParent.frame; 
    if (y < frame.size.height * .33) { 
     NSLog(@"top"); 
    } else if (y > frame.size.height * .67) { 
     NSLog(@"bottom"); 
    } else if (x < frame.size.width * .33) { 
     NSLog(@"left"); 
    } else if (x > frame.size.width * .67) { 
     NSLog(@"right"); 
    } else { 
     NSLog(@"center"); 
    } 
} 

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { 
    return YES; 
} 
+0

Grazie per questa risposta. Si rivolge più da vicino alle mie situazioni e offre una soluzione, dopo una dozzina di articoli letti. Grande pace del lavoro. – vedrano

+0

Sicuramente +1. Ottima spiegazione e buon codice, testato e funzionante con Swift 2.1 –

-2

È sempre stato un problema con i clic del mouse dall'inizio della gestione degli eventi.

È impossibile con un clic, per ogni software, determinare che un doppio clic sta per succedere.

Quindi, se si desidera gestire singolo clic e doppio clic, si dovrà fare la propria gestione doppio clic.

Tempo le istanze di clic singolo e generare un evento doppio clic del proprio.

Speriamo che possa trasferire al tocco nel tuo contesto.

+0

Attualmente in iOS UIGestureRecognizer ha funzionalità integrate per attendere la durata di un doppio tocco prima di lanciare un evento a tocco singolo. Ecco perché posso catturare correttamente i due eventi utilizzando due diversi riconoscitori di gesti. Semplicemente non so come ignorare il gesto di doppio tocco in modo da raggiungere UIWebView, o reindirizzare a lì, per mantenere il comportamento di zoom incorporato della visualizzazione web. – arlomedia

+0

@arlomedia [inoltro di eventi iOS] (https://www.google.com/search?btnG=1&pws=0&q=iOS+event+forwarding) –

+0

Ho esaminato i risultati di questa ricerca, ma non vedo nulla che aiuti il ​​mio situazione. Vedo alcuni suggerimenti che non dovrei provare ad inoltrare eventi agli oggetti UIKit, il che mi riporta alla parte "Forse c'è un modo più semplice" della mia domanda. – arlomedia