I want both my UIScrollView and its subviews to receive all touch events inside the subview. Each can respond in its own way.
Alternatively, if tap gestures were forwarded to subviews, all would be well.
A lot of people are struggling in this general area. Here are a few of the many related questions:
How does UIScrollView steal touches from its subviews
How to steal touches from UIScrollView?
How to Cancel Scrolling in UIScrollView
Incidentally, if I override hitTest:withEvent: in the scroll view, I do see the touches as long as userInteractionEnabled is YES. But that doesn't really solve my problem, because:
1) At that point, I don't know if it's a tap or not.
2) Sometimes I need to set userInteractionEnabled to NO.
EDIT: To clarify, yes, I want to treat taps differently from pans. Taps should be handled by subviews. Pans can be handled by the scroll view in the usual way.
Best Answer
First, a disclaimer. If you set
userInteractionEnabled
toNO
on theUIScrollView
, no touch events will be passed to the subviews. So far as I'm aware, there's no way around that with one exception: intercept touch events on the superview of theUIScrollView
, and specifically pass those events to the subviews ofUIScrollView
. To be honest, though, I don't know why you would want to do this. If you're wanting to disable specific UIScrollView functionality (like...well, scrolling) you can do that easily enough without disabling UserInteraction.If I understand your question, you need tap events to be processed by the UIScrollView and passed to the subviews? In any case (whatever the gesture is), I think what you're looking for is the protocol method gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: in the protocol
UIGestureRecognizerDelegate
. In your subviews, whatever gesture recognizers you have, set a delegate (probably whatever class is setting theUIGestureReconginzer
in the first place) on the gesture recognizer. Override the above method and returnYES
. Now, this gesture will be recognized along with any other recognizers that might have 'stolen' the gesture (in your case, a tap). Using this method you can even fine tune your code to only send certain kinds of gestures to the subviews or send the gesture only in certain situations. It gives you a lot of control. Just be sure to read about the method, especially this part:Of course, there's a caveat: This only applies to gesture recognizers. So you may still have problems if you're trying to use
touchesBegan:
,touchesEnded
, etc to process the touches. You can, of course, usehitTest:
to send raw touch events on to the subviews, but why? Why process the events using those methods inUIView
, when you can attach aUIGestureRecognizer
to a view and get all of that functionality for free? If you need touches processed in a way that no standardUIGestureRecognizer
can provide, subclassUIGestureRecognizer
and process the touches there. That way you get all the the functionality of aUIGestureRecognizer
along with your own custom touch processing. I really think Apple intended forUIGestureRecognizer
to replace most (if not all) of the custom touch processing code that developers use onUIView
. It allows for code-reuse and it's a lot easier to deal with when mitigating what code processes what touch event.