UIButton dentro de uma exibição que possui um UITapGestureRecognizer

Eu vejo com um UITapGestureRecognizer . Então, quando eu toco na vista, outra vista aparece acima desta vista. Esta nova visão tem três botões. Quando agora pressiono um desses botões, não obtenho a ação dos botões, só recebo a ação de gesto de toque. Então, não consigo mais usar esses botões. O que posso fazer para levar os events até esses botões? O estranho é que os botões ainda são destacados.

Eu não posso simplesmente remover o UITapGestureRecognizer depois que eu recebi o seu toque. Porque com ele a nova visão também pode ser removida. Significa que eu quero um comportamento como os controles de vídeo em canvas cheia .

Você pode definir seu controlador ou exibição (o que cria o reconhecedor de gesto) como o delegado do UITapGestureRecognizer . Em seguida, no delegado, você pode implementar o – -gestureRecognizer:shouldReceiveTouch: Na sua implementação, você pode testar se o toque pertence à sua nova subvisualização e, se isso acontecer, instrua o reconhecedor de gestos a ignorá-lo. Algo como o seguinte:

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { // test if our control subview is on-screen if (self.controlSubview.superview != nil) { if ([touch.view isDescendantOfView:self.controlSubview]) { // we touched our control surface return NO; // ignore the touch } } return YES; // handle the touch } 

No seguimento da resposta de Casey à resposta de Kevin Ballard:

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { if ([touch.view isKindOfClass:[UIControl class]]) { // we touched a button, slider, or other UIControl return NO; // ignore the touch } return YES; // handle the touch } 

Isso basicamente faz com que todos os tipos de controles do usuário, como botões, controles deslizantes etc., funcionem.

Encontrei esta resposta aqui: link

Você também pode usar

 tapRecognizer.cancelsTouchesInView = NO; 

Que impede que o reconhecedor de tap seja o único a capturar todas as torneiras

ATUALIZAÇÃO – Michael mencionou o link para a documentação que descreve esta propriedade: cancelsTouchesInView

Como resposta à resposta de Kevin Ballard, tive esse mesmo problema e acabei usando este código:

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { if ([touch.view isKindOfClass:[UIButton class]]){ return NO; } return YES; } 

Ele tem o mesmo efeito, mas isso funcionará em qualquer UIButton em qualquer profundidade de exibição (meu UIButton tinha várias exibições e o representante do UIGestureRecognizer não tinha uma referência a ele).

Encontrei outra maneira de fazer isso daqui . Ele detecta o toque se dentro de cada botão ou não.

(1) pointInside: withEvent: (2) locationInView:

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { // Don't recognize taps in the buttons return (![self.button1 pointInside:[touch locationInView:self.button1] withEvent:nil] && ![self.button2 pointInside:[touch locationInView:self.button2] withEvent:nil] && ![self.button3 pointInside:[touch locationInView:self.button3] withEvent:nil]); } 

No iOS 6.0 e posterior, as ações de controle padrão evitam o comportamento de reconhecimento de gestos sobreposto. Por exemplo, a ação padrão de um botão é um único toque. Se você tiver um único reconhecedor de gesto de toque anexado à vista pai de um botão e o usuário tocar no botão, o método de ação do botão receberá o evento de toque em vez do reconhecedor de gesto. Isso se aplica somente ao reconhecimento de gestos que se sobrepõe à ação padrão de um controle, que inclui: …..

Do doc de API da Apple

Essas respostas estavam incompletas. Eu tive que ler vários posts sobre como usar essa operação booleana.

No seu arquivo * .h, adicione isto

 @interface v1ViewController : UIViewController  

No seu arquivo * .m, adicione isto

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { NSLog(@"went here ..."); if ([touch.view isKindOfClass:[UIControl class]]) { // we touched a button, slider, or other UIControl return NO; // ignore the touch } return YES; // handle the touch } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. //tap gestrure UITapGestureRecognizer *tapGestRecog = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(screenTappedOnce)]; [tapGestRecog setNumberOfTapsRequired:1]; [self.view addGestureRecognizer:tapGestRecog]; // This line is very important. if You don't add it then your boolean operation will never get called tapGestRecog.delegate = self; } -(IBAction) screenTappedOnce { NSLog(@"screenTappedOnce ..."); } 

Aqui está a versão rápida da resposta de Kevin Ballard que funcionou para mim:

 func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool { if (scrollView.superview != nil) { if ((touch.view?.isDescendantOfView(scrollView)) != nil) { return false } } return true } 

Você pode impedir que o UITapGestureRecognizer cancele outros events (como o toque no botão) definindo o seguinte valor booleano:

  [tapRecognizer setCancelsTouchesInView:NO]; 

Se o seu cenário é assim:

Você tem uma visualização simples e alguns UIButtons, controles UITextField adicionados como subvisualizações para essa visualização. Agora você quer dispensar o teclado quando tocar em qualquer outro lugar na exibição, exceto nos controles (subvisualizações adicionadas)

Então a solução é:

Adicione o seguinte método ao seu XYZViewController.m (que tem sua visão)

 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self.view endEditing:YES]; } 

Otimizando a resposta do @ cdasher, você obtém

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { return ![touch.view isKindOfClass:[UIControl class]]; }