Domanda

So I realize that having nested scroll views at all it sort of a red flag, but the current setup of everything actually works quite well besides one small problem. One scroll view manages scrolling through a collection, while another handles zooming and panning on the entire collection view. This all works, but the small problem comes from when zooming in and panning downward, the scrollview pans while the collectionview scrolls, causing the view to scroll twice as fast, and not feel connected to your finger.

What I ideally want to happen is vertical scrolling is managed by the outer scroll view when panning is possible, and then handled by the inner scroll view when the outer one can no longer pan. I got very close by writing something like this:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView == _outerScrollView) {
        CGPoint offset = _outerScrollView.contentOffset;
        CGFloat height = _outerScrollView.frame.size.height;
        CGFloat contentHeight = _outerScrollView.contentSize.height;

        ScrollDirection scrollDirection;
        if (offset > _lastContentOffset){
            scrollDirection = ScrollDirectionUp;
        } else {
            scrollDirection = ScrollDirectionDown;
        }

        BOOL scrollIsAtTop =  offset.y <= 0;
        BOOL scrollIsAtBottom = offset.y + height >= contentHeight;

        //If there is a pan upward and we aren't at the top of the outer
        //scrollview cancel the gesture on the inner view
        //downward vice versa
        if (!((scrollIsAtTop && scrollDirection == ScrollDirectionUp) 
               || (scrollIsAtBottom && scrollDirection == ScrollDirectionDown))) {
            _innerCollectionView.panGestureRecognizer.enabled = NO;
            _innerCollectionView.panGestureRecognizer.enabled = YES;
        } 
    }
    _lastContentOffset = offset.y;
}

This ALMOST works, with one side effect of a big pan downward stops when it hits the bottom and requires the user to start a new gesture to continue scrolling with the inner collection. Ideally this transition would be smooth, but I'm having a hard time figuring out a way to do this. Again I realize scroll view inside scroll view is not ideal, but if I can fix this small problem everything will be good, rather than attempt to redesign the whole thing.

Any ideas on how I can handle the double scroll in a way that lets the pan gesture win, but cleanly transitions to the inner collection when the outer scroll view can no longer pan vertically?

È stato utile?

Soluzione

So, since I never got any answers, this is the solution I've been going with. Essentially if the inner collection view isn't at the top or bottom, I reset the y offset change the outer scroll view has in scrollViewDidScroll. Code looks like this:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView == _outerScrollView) {
        if (![self innerScrollIsAtTop] && ![self innerScrollIsAtBottom] && !self.allowOuterScroll) {
            [scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x, self.lastContentOffset)];
        }
        self.lastContentOffset = scrollView.contentOffset.y;
    }
}

using these 2 conveniences:

- (BOOL)innerScrollIsAtTop {
    return _innerCollectionView.contentOffset.y <= 0;
}

- (BOOL)innerScrollIsAtBottom {
    CGFloat zoom = self.zoomScale;
    CGFloat height = _innerCollectionView.frame.size.height;
    CGFloat contentHeight = _innerCollectionView.contentSize.height;
    CGPoint offset = _innerCollectionView.contentOffset;

    return offset.y + height / zoom >= contentHeight;
}

And you'll need 2 class variables, a float to hold the previous y content offset of the outer scroll, and a BOOL to hold whether you want to allow the outer scroll view to scroll, which you can set to YES while zooming or programatically scrolling. This solution fixes the double scroll, but does have a cumbersome hack within scrollviewDidScroll that may bite you later and you constantly need to work around, but for now this is the solution I've been using.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top