Funziona UIGestureRecognizer su un UIWebView?
-
04-10-2019 - |
Domanda
Sto tentando di ottenere un UIGestureRecognizer lavorare con un UIWebView che è una visualizzazione secondaria di un UIScrollView. Questo suona strano, ma quando ho il set numberOfTouchesRequired
a 2 fuochi selettore, ma quando numberOfTouchesRequired
è impostato su uno selettore non scatta.
Ecco il mio codice:
UITapGestureRecognizer *tap1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(select1:)];
tap1.numberOfTouchesRequired = 2;
tap1.numberOfTapsRequired = 1;
tap1.delegate = self;
[self.ans1WebView addGestureRecognizer:tap1];
[tap1 release];
- (void) select1:(UILongPressGestureRecognizer *)sender {
//Do Stuff
}
Ho confermato questo utilizzando l'esempio di Apple per UIGestureRecognizer e l'inserimento di un WebView nella loro pennino. Il loro codice di rubinetto funziona ovunque, ma all'interno dell'area del WebView.
Soluzione
Da quello che ho visto, UIWebView non gioca bene con gli altri. Per di riconoscimento gesto, si potrebbe provare a tornare SI da:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
Ho dovuto essere compatibile con 3,0 così ho finito per fare tutta la movimentazione con JavaScript all'interno del UIWebView gesto. Non è una buona soluzione, ma ha funzionato per le mie esigenze. Sono stato in grado di catturare una pressione prolungata su un elemento, così come rubinetto, strisciare, stringere e Ruota. Naturalmente, stavo usando solo contenuto locale.
Modifica:
Si può guardare a PhoneGap per un esempio di invio di messaggi al delegato della UIWebView. In poche parole, si utilizza document.location = "myscheme:mycommand?myarguments"
quindi analizzare il comando e gli argomenti da questo delegato di callback:
-(BOOL) webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType {
if ( [[[inRequest URL] absoluteString] hasPrefix:@"myscheme:"] ) {
//.. parse arguments
return NO;
}
}
Si può vedere nel codice PhoneGap che hanno istituito una coda e timer per inviare i messaggi. A seconda dell'uso, potrebbe essere necessario fare la stessa cosa. Ci sono altre domande sul SO su questo argomento.
Questa è la gestione degli eventi di documentazione . Nel mio caso ho aggiunto listener di eventi per document
da <body onload="myloader();">
function myloader() {
document.addEventListener( 'touchcancel' , touch_cancel , false );
document.addEventListener( 'touchstart' , touch_start , false );
document.addEventListener( 'touchmove' , touch_move , false );
document.addEventListener( 'touchend' , touch_end , false );
};
Il trattamento vero e proprio evento dipende molto dalle vostre esigenze. Ogni gestore di eventi riceverà una TouchEvent con una proprietà tocchi in cui ogni elemento è un tocco . È possibile registrare l'ora di inizio e la posizione nel vostro gestore TouchStart. Se i tocchi spostarsi lontano o un importo errato di tempo passa non è un tocco lungo.
WebKit può cercare di gestire una lunga tocco per iniziare una selezione e copiare. Nel vostro gestore di eventi è possibile utilizzare event.preventDefault();
per fermare il comportamento predefinito. Ho anche trovato la proprietà -webkit-user-select:none
css a portata di mano per alcune cose.
var touch = {};
function touch_start( event /*TouchEvent*/ {
event.preventDefault();
touch = {};
touch.startX = event.touches.item(0).pageX;
touch.startY = event.touches.item(0).pageY;
touch.startT = ( new Date() ).getTime();
}
Questo è solo il secondo progetto ho usato con javascript. Si possono trovare esempi migliori altrove.
Come si può vedere questa non è una rapida risposta al vostro problema. Sono abbastanza soddisfatto dei risultati che ho ottenuto. L'html con cui stavo lavorando avuto nessun elementi interattivi al di là di un link o due.
Altri suggerimenti
UIWebView ha le proprie opinioni personali, che ha anche attaccato di riconoscimento dei gesti. Quindi, regole di precedenza mantenere qualsiasi di riconoscimento gesto aggiunti a un UIWebView di funzionare correttamente.
Una possibilità è quella di implementare il protocollo UIGestureRecognizerDelegate e implementare il metodo gestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizer. Ritorno SI da questo metodo per altri gesti tap. In questo modo avrai il tuo gestore di rubinetto chiamato, e la vista web sarà ancora ottenere la sua chiamata.
Si tratta di una soluzione un po 'hack-ish, ma funziona.
UIWebView ha un sacco di sistemi di riconoscimento dei gesti interni che normalmente non possono accedere senza utilizzare API private. È li ottiene gratuitamente, però, quando si implementa gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:
. A quel punto, si può dire tutte le UITapGestureRecognizers interne al fuoco solo quando il proprio UITapGestureRecognizer è riuscito. Hai solo farlo una volta e poi rimuovere il delegato dal proprio gesto riconoscitore. Il risultato è che si può ancora pan e scorrere il vostro WebView, ma non riceverà più alcun gesti (singolo) tap.
- (void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
// view is your UIViewController's view that contains your UIWebView as a subview
[self.view addGestureRecognizer:tap];
tap.delegate = self;
}
- (void)handleTapGesture:(UITapGestureRecognizer *)gestureRecognizer
{
NSLog(@"tap!");
// this is called after gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: so we can safely remove the delegate here
if (gestureRecognizer.delegate) {
NSLog(@"Removing delegate...");
gestureRecognizer.delegate = nil;
}
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if ([otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
[otherGestureRecognizer requireGestureRecognizerToFail:gestureRecognizer];
NSLog(@"added failure requirement to: %@", otherGestureRecognizer);
}
return YES;
}
Enjoy!
ho avuto lo stesso problema. Questa soluzione ha funzionato per me:
1) Assicurarsi di aggiungere il protocollo per l'interfaccia: UIGestureRecognizerDelegate ad esempio:
@interface ViewController : UIViewController <SlideViewProtocol, UIGestureRecognizerDelegate>
2) Aggiungere questa riga di codice
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES
}
3) gesto Setup
UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(nextSlide)];
swipeGesture.numberOfTouchesRequired = 1;
swipeGesture.direction = (UISwipeGestureRecognizerDirectionLeft);
swipeGesture.cancelsTouchesInView = YES; [swipeGesture setDelegate:self];
[self.view addGestureRecognizer:swipeGesture];
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer {
return YES;
}
Un altro modo è quello di mettere un UIButton trasparente sopra UIWebView e rubinetti maniglia da questo pulsante. In alcuni casi potrebbe essere una buona soluzione.
UIWebView webView = [UIWebView new];
//...
UIButton *transparentButton = [UIButton buttonWithType:UIButtonTypeCustom];
[transparentButton addTarget:self action:@selector(buttonTapped) forControlEvents:(UIControlEventTouchUpInside)];
transparentButton.frame = webView.frame;
transparentButton.layer.backgroundColor = [[UIColor clearColor] CGColor];
[self.view transparentButton];
Si può anche trovare la mia risposta qui utile. E 'un esempio di lavoro di gestire il gesto pizzico in javascript di UIWebView.
(Si potrebbe comunicare gli eventi Torna alla Objective-C se si voleva. Vedi la mia risposta qui .)