views:

362

answers:

2

I have a view hierarchy that is layed out as follows:

parentView

 scrollView

    contentViewA

    containerView

         contentViewB

         contentViewC

I want contentViewB to respond to touches. Unfortunately scrollView makes this almost impossible because it tries to ingest the touches itself making touch response of contentViewB spotty.

So, instead, I want to intercept all touches in the parentView, manipulate contentViewB directly, and then pass the touches on to scrollView so it can do its thing.

Can someone please show me the correct way to pull this off?

Thanks in advance.

Cheers, Doug

UPDATE:

I did a bit more digging and found the property canCancelContentTouches which seems to work wonders. I'm using IB so I unchecked "Cancellable Content Touches" in IB - first tab of the Scroll View Attribute Inspector. Now, when I run the app, touches appear to be arriving at contentViewB reliably.

Here's how the UIScrollView docs describe this property:

Discussion If the value of this property is YES and a view in the content has begun tracking a finger touching it, and if the user drags the finger enough to initiate a scroll, the view receives a touchesCancelled:withEvent: message and the scroll view handles the touch as a scroll. If the value of this property is NO, the scroll view does not scroll regardless of finger movement once the content view starts tracking.

Rather opaque huh? Anyway, it seems to work.

+1  A: 

To stop the scroll view from intercepting the touch events, set the userInteractionEnabled property like so:

scrollView.userInteractionEnabled = NO;
Phil Nash
Thanks Phil. Which view in the hierarchy should toggle scrollView.userInteractionEnabled?
dugla
Also, via what method - hitTest:?, touchesBegan:withEvent:?. Thanks.
dugla
Who owns the scroll view (usually a view contoller). When it's first created and set as a subview is usually when you'd do it - or do you need to update this at different times?
Phil Nash
Indeed a viewController owns the scrollView. The challenge is I need to toggle the scrollView.userInteractionEnabled. This is because I have configured the scrollView to only scroll horizontally but have implemented a trivial vertical scroller from scratch for contentViewB.
dugla
ok. At some point you must know when to switch. You can then call a method on the view controller (which you will implement) that will toggle the property. Best to store the scroll view as a member of the view controller if you're not already doing so.
Phil Nash
see my comment to your original question
Phil Nash
Phil, See the update to the question I wrote. What do you think of this approach?
dugla
Ok, lets see if I've got this. If I go with your approach, I would set scrollView.userInteractionEnabled = NO in my implementation touchesBegan: and scrollView.userInteractionEnabled = YES in touchesEnded:. I would implement the touch sequence methods in some reasonable class such as parentView. Sound about right?
dugla
no, now that I have a slightly better understanding of what you're trying to do (I think), I don't think this is the right approach. The ability to intepret touches by a scroll view and its subviews, depending on whether you are actually scrolling, is baked in. I don't have access to my dev machine at the moment to check the specifics, but will have a look later if you're still having trouble
Phil Nash
A: 

Another way of doing this is to add another subview to your ui so it looks like so :

parentView
  scrollView
    contentViewA
      containerView
        contentViewB
        contentViewC
  touchGrabber

and, in touchGrabber, detect all the touches that you want (by subclassing UIView)

This is more complicated than Phil Nash's solution but has the advantage that you can add/remove other views from your parentView without having to deal with their userInteractionEnabled value - this is useful if you have a third party library adding views for example.

However, if you definately only going to have the scrollView, Phil Nash's answer is the way forward!

Thanks,

Sam

deanWombourne