views:

124

answers:

1

I have a view, that is able to go back to the previous view.

Let's say this is a questionnaire. So my main view is the questionnaireView(Controller), and it has a subview which shows a question with 2 possible answers. When one answers the question, one presses next, and the questionnaireView(Controller) shows the next question in that particular subview. Simple, right?

Okay, now imagine having to accomodate up to 10 anwers for a particular question. This will require implementing a scrollview in the subview, to accomodate for the question + all answers.

Now my question: I want questionnaireView(Controller) to receive notice of horizontal swipes (next/previous question), but I want all other touches (taps, for the radiobuttons of the answers, and vertical swipes for the scrollview) to go through...

Any idea's how to go about this? I have tried about 5 different approaches and broke my head and motivation on each on of 'em :/ Last one (and most simple one), was simply adding another subview to questionnaireView(Controller), overlaying the question+answer view.

This kindly catches all the touchesBegan/Moved/Ended/Cancelled for me, but even if I just put a forward in -each- of thoses methods ([self nextResponder] ...) the underlying view (with the answers, and the scrollview) won't respond anymore...

I'm kinda lost on this, and am thinking of writing my own Scrollview someday, since UIScrollView is the most terrible monster faced by iPhone devvers :P

Mind you, I am supporting iPhone OS 3.0 and up, so the new gesture APIs are no-go.

+1  A: 

I'm not sure what you mean by "a forward in -each- of thoses methods". I'm not sure that nextResponder is the correct thing to forward them to either.

The problem is that touches are supposed to be "owned" by a single view throughout their lifetime. I'm not sure how UIScrollView or gesture recognizers are implemented, but I'm pretty sure they do more than you're supposed to do on your own.

I'd override questionnaireView's hitTest:withEvent: to return self. In your touchesBegan:withEvent:, call [super hitTest:[touch locationInView:self] withEvent:event] and store the subview that "owns" it. In touchesMoved:withEvent:, forward the touch to the relevant subview, but if you detect a gesture, "forget" the subview that owns the touch and instead call touchesCancelled:withEvent:. In touchesEnded/Cancelled:withEvent:, forward it to the subview and then forget the owning subview.

It's icky, but it mostly works. Some things it gets wrong (from the perspective of subviews):

  • -[UIEvent touchesForView:] will return the QuestionnaireView.
  • UITouch.view will return the QuestionnaireView
  • UITouch.phase might not be UITouchPhaseCancelled in touchesCancelled:withEvent: (if you detect the gesture and cancel the touch). *
tc.
I can't get it to work yet, this is my code so far: http://pastebin.com/V4eZQj90.My problem is that the touchesEnded suffers from an eternal loop, even though I test if the "nextResponder" UIView is not equal to self...
StijnSpijker
It looks okay to me. What loops?Also note that if you want to support multi-touch, you'll need to store the "next responder" for each touch individually.
tc.