12

I have a problem where my UITapGestureRecognizer on my UILabels in a content view in my UIScrollView is not calling it's methods.

The view hierarchy is as follows:

  • scrollView (UIScrollView)
    • contentView (UIView)
      • testLabel (UILabel) - here is where the UITapGestureRecognizer is attached

I have distilled the code down to an example to highlight the problem

// Set scrollview size - Added in Storyboad
[scrollView setContentSize:CGSizeMake([arrayOfVerbs count]*self.view.frame.size.width, scrollView.contentSize.height)];
[scrollView setCanCancelContentTouches:YES]; // Tried both yes and no
[scrollView setPagingEnabled:YES];

// Add content view
UIView *contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, scrollView.contentSize.width, scrollView.contentSize.height)];
[scrollView addSubview:contentView];

// Add test UILabel
UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 100)];
[testLabel setBackgroundColor:[UIColor redColor]];
[testLabel setText:@"Test touch"];
[testLabel setUserInteractionEnabled:YES];
[contentView addSubview:testLabel];

// Add gesture recogniser
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(playSound:)];
singleTap.numberOfTapsRequired = 1;
[testLabel addGestureRecognizer:singleTap];

And this is the method that the tap gesture recogniser should call

- (void)playSound:(UITapGestureRecognizer *)sender {

    NSLog(@"play sound");

    if(sender.state == UIGestureRecognizerStateEnded)
    {
        int pronounNumber = [sender.view tag];
        int exampleNumber = (int)sender.view.frame.origin.x%(int)self.view.frame.size.width;

        NSLog(@"Pronoun is %i and example is %i", pronounNumber, exampleNumber);
    }
}

This method is never called when I tried to touch on the UILabel.

I have tried setting the property canCancelContentTouches to both YES and NO on the scroll view as suggested by this thread, but it's still not working.

The strange thing is, if I add a UILabel outside of the scrollView, then the gesture recogniser works! So the problem only occurs in my contentView which is a subview of my scrollView.

I am using auto-layout, if that might be any difference?

Thanks!

Community
  • 1
  • 1
Joseph Williamson
  • 771
  • 1
  • 6
  • 18
  • 2
    Try setting [contentView setClipBounds:YES]; and see whether your `Label` inside the `ContentView` is visible, if not then your `Label` is not in touching area, adjust your resizing properties.. – iphonic Jul 18 '13 at 11:05

3 Answers3

15

The scroll view also has a gesture recogniser. By default, only 1 gesture recognizer can be handling touches at any one time. You need to make yourself the delegate of your gesture and then implement gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: to return YES. This will allow it to work at the same time as the scroll view.

Wain
  • 118,658
  • 15
  • 128
  • 151
  • 1
    OK, so I set `singleTap.delegate = self;` and implemented `UIGestureRecognizerDelegate` in my .h file, and add `gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:`, but it still doesn't work. – Joseph Williamson Jul 18 '13 at 11:00
  • 3
    Is the delegate method being called? What is the size of the content view (log it)? – Wain Jul 18 '13 at 11:05
  • 2
    OMG! You got it! it was `contentView size – Joseph Williamson Jul 18 '13 at 11:10
  • Strangely enough, @wain, it DOES seem to work (these days anyway) if you add a tap (UITapGestureRecognizer) to "cells" of a stack view inside a scrollview. Without using shouldRecognizeSimultaneously. I don't know why. – Fattie Jan 14 '17 at 20:08
  • 2
    For anyone reading this I had a fascinating obscure problem. I was generating UIViewControllers and their views on the fly, and inserting them in a scroll view. Of course, view controllers - per se - are not particularly retained when you create them! the view remains but the VC is gone, unless you keep it. – Fattie Jan 14 '17 at 20:09
2

Add delegate to tagGestures,

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

EDIT:-

contentView.userInteractionEnabled = YES;

put this line your code it'l work.

Balu
  • 8,470
  • 2
  • 24
  • 41
  • Hi, I just tried setting the delegate to self, and implemented `` protocol and - `(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch` method. Still doesn't work, also why would I need to implement a delegate for it when I don't need it for UILabels outside of the scrollview? – Joseph Williamson Jul 18 '13 at 10:49
  • @Joseph Williamson:have you added last line of code in my answer?once add it and check. – Balu Jul 18 '13 at 10:51
  • once check your scrollView view frame. – Balu Jul 18 '13 at 11:02
  • Sorry, what do you mean by checking my scrollview view frame? – Joseph Williamson Jul 18 '13 at 11:06
  • @Joseph Williamson:Problem is either with contentView frame or scrollview frame once give static values and check. – Balu Jul 18 '13 at 11:13
-3
[yourlabel.addGestureRecognizer:tapGestureDeFromage];

should add the gesture explicitly to your labels.

Exothug
  • 339
  • 4
  • 18