2013-03-17 16 views
27

Ho un UIView (la 'vista del contenitore') che contiene diverse 'viste secondarie'. Voglio aggiungere un UITapGestureRecognizer alla vista del contenitore, in modo tale che venga attivato quando tocco la regione all'interno della vista contenitore ma all'esterno delle visualizzazioni secondarie.Escludi le visualizzazioni secondarie da UIGestureRecognizer

Al momento, toccando qualsiasi punto all'interno della vista contenitore, incluso all'interno delle visualizzazioni secondarie, viene attivato il riconoscimento dei gesti.

L'implementazione simile a questa: Nel controllore:

ContainerView *containerView = [[ContainerView alloc] initWithSubViews:array]; 
UITapGestureRecognizer *tap = [UITapGestureRecognizer alloc] initWithTarget:self action:@selector(someSelector)]; 
[containerView addGestureRecognizer:tap]; 
[self.view addSubView:containerView]; 

In ContainerView.m

-(id)initWithSubviews:(NSArray *)array { 
    for (subView *s in array) { 
     [self addSubView:s]; 
    } 
    return self; 
} 

Credo che il problema si verifica perché il sistema di riconoscimento gesto è aggiunto dopo gli subviews sono. Se ciò è vero, la soluzione richiederebbe la rottura del metodo initWithSubViews in due separati, che preferirei evitare.

Thank You

risposta

9

iOS 6 introduce una nuova grande caratteristica che risolve questo problema esatto - un UIView (visualizzazione secondaria) può restituire NO da gestureRecognizerShouldBegin: (gesto riconoscitore collegato a una superview). In effetti, questo è l'impostazione predefinita per alcune sottoclassi di UIView rispetto ad alcuni riconoscitori di gesti già (ad esempio un UIButton in relazione a un UITapGestureRecognizer collegato a una superview).

vedi il mio libro su questo argomento: http://www.apeth.com/iOSBook/ch18.html#_gesture_recognizers

0

Se è stato aggiunto UITapGestureRecognizer per ContainerView, si deve rispondere con tutto ContainerView. Non gli dispiacerà le sue sottoview.

Controllare la posizione del gesto, se è nella posizione della sottoview, saltare semplicemente le azioni del gesto.

- (void) tapGestureHandler:(UIGestureRecognizer *) gestureRecognizer { 


    CGPoint tapPoint = [gestureRecognizer locationInView:nil]; 

    //check your tapPoint contains ur subview frame, skip.else do ur actions 
} 
+0

Questo è costoso e peloso se è necessario controllare molte sottoview. – CodaFi

+0

yup..Vedo .. Non vedo altre buone soluzioni .. se ne avete, sentitevi liberi di condividere .. :) –

0

aggiunto:

ho solo pensato a qualcosa di meglio.

nel gestore

-(void)tapGestureHandler:(UITapGestureHandler)gesture 

controllo se gesture.view è il superview. restituirà le sottoview se vengono visualizzate le visualizzazioni secondarie.

========================================= ======

Suggerirei di ignorare all'interno del superview.

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 

questo viene chiamato per determinare se un gesto rientra in una vista

vedere la risposta a questa domanda per vedere come si comporta per default.

Event handling for iOS - how hitTest:withEvent: and pointInside:withEvent: are related?

è possibile verificare se il punto è in una delle sue subviews. se sì, restituire nil, altrimenti restituire se stessi.

O

in ciascuna delle subviews, aggiungere un riconoscitore tapgesture che non fa nulla. il riconoscitore di gesti di una sottoview annullerà di default il riconoscitore di gesti della sua superview. terrei d'occhio l'impronta della memoria se ci sono molte sottoview.

+0

Purtroppo non penso che funzioni. Secondo i documenti, gesture.view ti dà "La vista a cui è collegato il riconoscitore di gesti". che dà l'intera vista del contenitore e non la sottoview. La seconda opzione sembra promettente, ci provo. –

+0

Ottimo, ho funzionato usando il metodo hitTest: withEvent. Vedi post qui sotto. –

11

sono riuscito a farlo funzionare nel modo seguente:

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureHandler:)]; 

// ... 

-(void) tapGestureHandler:(UITapGestureRecognizer *)sender { 
    CGPoint point = [sender locationInView:sender.view]; 
    UIView *viewTouched = [sender.view hitTest:point withEvent:nil]; 
    if ([viewTouched isKindOfClass:[ThingIDontWantTouched class]]) { 
     // Do nothing; 
    } else { 
     // respond to touch action 
    } 
} 
37

ho usato il modo più semplice di seguito. Funziona perfettamente!

Implementare la funzione UIGestureRecognizerDelegate, accetta solo i touchs sul superview, non accettano touchs sul subviews:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch 
{ 
    if (touch.view != _mySuperView) { // accept only touchs on superview, not accept touchs on subviews 
     return NO; 
    } 

    return YES; 
} 
4

ricordarsi di aggiungere e impostare il metodo delegato -

Nel file .h di UIViewController includono questo delegato

Quindi dove stai creando ur oggetto tapGesture, (entro viewDidLoad per esempio)

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(actionMethodYouWantToHappenOnTap)]; 

    tap.delegate = self; //Remember to set delegate! Otherwise the delegate method won't get called. 

    [self.view addGestureRecognizer:tap]; 

Ricordando di impostare il metodo delegato tap.delegate = self; allora il metodo delegato per rubinetto verrà ora sparare alla spina.

All'interno di questo metodo di gestire quando si desidera il riconoscimento del rubinetto gesto da utilizzare, nel mio codice ho voluto ignorare un rubinetto se una particolare visualizzazione secondaria era visibile

-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{ 

    if (!mySubview.hidden){ 
    return NO; //This fired if said subview was visible, though whatever the condition of where and when you want tap to work, can be handled within this delegate method. 
    } 

    return YES; 
} 

Spero che questo aiuta chiunque altro con lo stesso problema. Ricordare di impostare il metodo delegato che ho trovato era qualcosa che è facilmente trascurato.

Acclamazioni

2

sacco di risposte, l'aggiunta di un'altra soluzione alternativa. Inizializzare la vista tag dei subviews non si desidera ricevere tocchi da come 1 e procedere come segue:

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; 
    tap.delegate = self; 
    [self.view addGestureRecognizer:tap]; 
} 

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch 
{ 
    if (touch.view.tag == 1) { 
     return NO; 
    } 
    return YES; 
} 

-(void)handleTap:(id)sender 
{ 
//Handle tap... 
} 

In questo modo, il tocco gesto saranno ricevuti solo dai panorami richiesti da.

Problemi correlati