2
votes

iOS 8, Swift. I'm trying to have a vertically scrolling view over a horizontally scrolling view. They're both UIScrollViews. The vertical scroll view is there to allow swiping up a view from the bottom. There is a spacer view on top using auto layout that is 1 pixel wide but the screens height.

This works fine until the underlying view is itself a scrollview to support horizontal scrolling.

I somehow need to pass the left/right pan gesture to the subview which is a UIScrollView.

Currently, the top level vertical scroll view is capturing all the gestures and not letting the underlying horizontal scroll view see the events.

I've tried various combinations of hitTest, gestureRecognizer delegate methods, scrollview subclassing but having come up with a nice clean solution.

I can use hitTest to pass events to the underlying horizontal scroll view when tapping the empty space at the top of the vertical scroll view, but then the vertical scroll view never processes a pan or swipe up to reveal the content that should appear on a swipe up.

Ideally, I'd like the top vertical scroll view to only handle pan up/down, and pass left/right pan to subview when the vertical scroll view is at the top.

1
Okay so touch events are a problem, yessir, I don't have time to elaborate on how I would fix this, but I have a few tips for you, first off, set drectionalLockEnabled to TRUE for both scroll views, and secondly, set in your scrollviewDidScrollMethod, have you tried this, assuming you even had 1 touch even pass through: if (scrollView ==_verticalScrollView) { [_verticalScrollView setContentOffset:CGPointMake(0, scrollView.contentOffset.y)]; } else{ [_horizontalScrollView setContentOffset:CGPointMake(scrollView.contentOffset.x, 0)];Larry Pickles
and one more idea, and this is how I do this, is to use three scrollViews, 1 scrollview that is empty and clear that sits on top of the other two scrollvies and this scrollview will allow movement up and down and all around, then you do this: [_verticalScrollView setContentOffset:CGPointMake(0, _invisibleScrollView.contentOffset.y)]; [_horizontalScrollView setContentOffset:CGPointMake(_invisibleScrollView.contentOffset.x, 0)]; and of course, you don't allow touch events on the horizontal or veritical scrollviews, just the top scrollview that is semi invisible,Larry Pickles
Part of the problem is that I don't know how to have the top scroll view conditionally pass pan gesture to the underlying horizontal scroll view. If I override hitTest, I can make all events go to the lower SV, none to the upper. I need to conditionally to let horizontal pan go to the lower scroll view.David
What I'm saying is that I don't think you need to, if the TOP invisible UIScrollView intercepts the events, all of them, and then, in your ScrollViewDidScroll, you just offset the horizontal scrollview and the vertical scrollview by the swipe direction of the top scrollview, this is a nasty hack, but it's worked for me, make the top semi-invisible scroll directional lock enabled, and then pass the offset to the other scroll views. in the ScrollViewDidScroll. I'll GIST what i mean, one secLarry Pickles

1 Answers

4
votes

Here's a brief method that may help you out:

Obj-C:

create scroll view that is invisible, and then pass the offset of the invisible scroll view or the touch events to the scroll views below depending on the offset of the touch events on the top invisible scroll view that covers the two underlying scroll views:

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
    [_verticalScrollView setContentOffset:CGPointMake(0, _insivibleScrollView.contentOffset.y)];
    [_horizontalScrollView setContentOffset:CGPointMake(_insivibleScrollView.contentOffset.x, 0)];
}

You create an invisible scroll view, and by invisible, I mean you may have to keep the alpha value at like 0.01. You don't allow user interaction for the horizontal and vertical scroll views, but instead use the method above so that when the user touches the invisible scroll view you translate those touches to the scroll views below that are locked down to respond to only the offset of the invisible scroll view. As you've stated in your comment, there's probably more to this answer for your individual needs, but this is the basic "foundation" that will give you the effect that you probably want.

Swift:

Same method as above, but here's the function that you'll need:

func scrollViewDidScroll(scrollView: UIScrollView!) {
    verticalScrollView.contentOffset = CGPointMake(0, invisibleScrollView.contentOffset.y)
    horizontalScrollView.contentOffset = CGPointMake(invisibleScrollView.contentOffset.x, 0)
}