2
votes

SOLVED: see comments for what the problem was

I am implementing a subclass on UIScrollView which will be a horizontally scrolling row of subviews/"cells". Basically a horizontally scrolling "table view" like element. Each of the subviews/"cells" in the UIScrollView content view have a UIGestureRecognizer attached to them so that when a person touches one of them, the UIGestureRecognizer will trigger.

The problem is that when a person has scrolled away from the contentView origin, i.e., the UIScrollView returns a contentOffset where x is other than 0, any of the new subviews/"cells" that scroll in from the right do not trigger the UIGestureRecognizer when touched. All the subviews DO have their UIGestureRecognizer.

Example, let's say I am display a row of 80x80 icons and my contentSize is 1600,80 for a row of 20 icons. The UIScrollView is 320,80 so it will show 4 of the icons. The initial 4 icons are touchable and the UIGestureRecognizer fires on each one. The user scrolls to the left, i.e., new icons come in from the right. These new icons (Subviews) are created and added in to the contentView I use in the UIScrollView the same way as the original 4. But the new icons (subviews) that were not in the original bounds do not trigger. I implement my own queue/dequeue of the subviews analogous to what a tableview does so if I have scrolled over by place #15, none of the original icons (subviews) is even in the contentView as the subviews are recycled (and old UIGestureRecognizers removed and new ones attached when it is pulled off the queue and reused) and none of these are touchable and trigger the UIGestureRecognizer.

HOWEVER, if the user then scrolls back to the beginning, even though those cells are newly added to the contentView, they ARE touchable as long as their bounds are within the original frame of the UIScrollView and the UIView contentView I used to aggregate inside the scroll view. So it seems that it is dependent on the frame of each subview and whether or not it lies within the frame of the scrollview.

Everything displays fine -- as it scrolls the contentOffset changes and I remove and add subviews. It is just the UIGestureRecognizers attached to each subview that are not triggering and are position dependent on being within the original bounds of the Scrollview before it starts scrolling.

I've been scratching my head on this all day, and half a day yesterday) and narrowing it down to being position dependent on not something else.

I would post code but am not sure what to post as there is a lot of code that runs this.

2
Interestingly, touchesBegan:withEvent: only triggers for the first 4 subviews (the ones initially visible and that are within the frame boundary of the scrollview) and does not trigger after scrolling for ones that scroll into place. And when it triggers on the content view, the hitTest:locationInView: does not find any embedded subviews for the ones that scroll in and are not part of the initial non-scrolled view.chadbag
I had created a single UIView to contain all my content and this was not passing the touches in beyond the initial non-scrolled location though it was displaying things fine. When I got rid of this container UIView and added the subview cells directly to the UIScrollView subclass, things started working.chadbag
You should add this comment as an answer and mark it correct, so that I could upvote it. It helped me, thanks! :)Pirkka Esko

2 Answers

1
votes

I had subclassed UIView, added it inside UIScrollView and the gesture recognizers of my subclassed UIView's subviews were not firing - except for the ones that were initially visible as before any scrolling.

The simple fix was to add the UIView's subview directly to the UIScrollView instead of my subclassed UIView. Before I was doing

    // add to view
    [self addSubview:imageView];

so I fixed it with

    // add to view - we're adding to the superview directly
    [self.superview addSubview:imageView];

This way I could still keep the logic that populates my UIScrolView in a separate class.

1
votes

I had the same symptoms described here. Rather than remove the intermediate view and add the subviews directly to the scrollview, per the accepted answer, I got things working by resizing the intermediate views.

Previously, I had been setting the content size of the scroll view, and adding the subviews to the intermediate view, but not resizing the intermediate view. By setting the frame of the intermediate view correctly, my gesture recognizers began functioning correctly.

I think that normally the subviews would get a chance to handle the event, and then pass unprocessed events up the chain. Inside a scroll view, however, the event ends up going from the scroll view down the view chain, and the intermediate view tosses out events beyond their bounds, hence the gestures not working initially.

Hope this helps anyone else who runs into this issue, as it was frustrating to track down.