14

I have UIViewController on my simple storyboard IPad project which contains UIScrollView which is placed over entire surface (1024 x 768). I have created 3 XIB files which are UIViews which my application loads on start in viewDidLoad and add them into UIScrollView. Each of these 3 XIB files contains only one UIButton.

This is hierarchy:

~ UIViewController (UIViewControllerClass is class for this UIViewController)

~~ UIScrollView (contains 3 identical UIViews)

~~~ UIView (UIViewClass is File's Owner for this XIB file)

~~~~ UIButton

I would like that my UIViewControllerClass becomes aware of both: touch anywhere on UIScrollView component AND if UIScrollView is touched, if UIButton inside of UIView in UIScrollView is touched, to have information that exactly that button is touched.

I made IBAction inside UIViewClass for touch on UIButton inside UIView in UIScrollView and when I set User Interaction Enabled = YES on all elements (UIViewController, UIView and UIScrollView) this method is called as it should.

But at this point my UIViewControllerClass isn't aware that touch occurred inside UIScrollView on that UIButton. I made touch recognizer like this:

UITapGestureRecognizer *touch = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTouch)];
touch.numberOfTouchesRequired = 1;

and added it to UIScrollView component. In this way I am able to detect touch event on UIScrollView component in UIViewControllerClass, but touch event handler for UIButton in UIView which is inside UIScrollView isn't called anymore.

So, I need to have these two informations in UIViewControllerClass:

  • Touch on UIScrollView component was made
  • Touch on UIButton in UIView which is inside UIScrollView (if this button was touched) was made

I suppose that attaching touch event recognizer to entire UIScrollView component isn't solution, since it disables all touch event handlers I wrote inside UIViewClass.

I think solution is that somehow touches which are made on components in UIView inside UIScrollView should be sent up to UIViewControllerClass, but I didn't found a way to do this.

If anyone can help me, I'd be very grateful. Thanks in advance.


[edit #1: ANSWER by Zheng]

Tap gesture must have cancelsTouchesInView option set to NO!

For my case above, this line solves everything:

touch.cancelsTouchesInView = NO;

Many thanks to Zheng.

uerceg
  • 4,637
  • 6
  • 45
  • 63

3 Answers3

18

I don't know if this works for you or not, but I've given an answer about touch events for views inside scrollview here:

Dismissing the keyboard in a UIScrollView

The idea is to tell the scrollView not to swallow up all tap gestures within the scroll view area.

I'll paste the code here anyways, hopefully it fixes your problem:

UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)];

// prevents the scroll view from swallowing up the touch event of child buttons
tapGesture.cancelsTouchesInView = NO;    

[pageScrollView addGestureRecognizer:tapGesture];

[tapGesture release];

...

// method to hide keyboard when user taps on a scrollview
-(void)hideKeyboard
{
    [myTextFieldInScrollView resignFirstResponder];
}
Community
  • 1
  • 1
Zhang
  • 11,549
  • 7
  • 57
  • 87
  • Thank you very much! This problem of yours isn't related to mine, but contains one VERY important line for me with option I didn't know that UITapGestureRecognizer has - cancelsTouchesInView. I didn't know that this option is set to YES by default, and now when I set it to NO, I am able to detect touch on UIScrollView and also if element which is touched inside UIScrollView has it's touch handler, that handler is being called too. Thank you once more, you solved my problem with that line. – uerceg Sep 03 '12 at 09:15
3

You can subclass your UIScrollView and override the method - hitTest:withEvent: which is called by the system to determine which view will handle the event. Whenever it is called, you can assume that a touch event occurred inside the scroll view, and by calling the super implementation, you can get the view which would normally process the event.

Guillaume
  • 4,331
  • 2
  • 28
  • 31
  • Thank you very much for the answer, but I checked for answers on my question when Zhang also answered me and I tried his solution which worked for me. Thanks once more! – uerceg Sep 03 '12 at 09:13
0

you can capture any kind of gestures in the UIscrollView. Make sure you also handle some of the default properties as well like set cancelsTouchesInView property to false, it is true by default. Also give some tag nos to your sub views to distinguish in selectors. & also enable their User interaction to true.

let tap = UITapGestureRecognizer(target: self, action:

selector(didTapByUser(_:)))

Ash
  • 5,525
  • 1
  • 40
  • 34