处理嵌套UIScrollViews中的冲突手势

时间:2014-04-18 14:08:01

标签: ios objective-c uiscrollview uicollectionview uipangesturerecognizer

所以我意识到嵌套滚动视图根本就是一个红色的标志,但除了一个小问题之外,当前设置的一切实际上都很好。一个滚动视图管理滚动集合,而另一个滚动视图处理整个集合视图上的缩放和平移。这一切都有效,但小问题来自放大和向下平移时,滚动视图在收集视图滚动时平移,导致视图滚动速度提高两倍,并且感觉不到手指连接。

我理想情况下想要发生的是垂直滚动由外部滚动视图在平移时进行管理,然后在外部滚动视图无法平移时由内部滚动视图处理。我写得非常接近:

- (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;
}

这个 ALMOST 可以正常工作,当它碰到底部并且要求用户开始一个新的手势继续滚动内部集合时,大盘的一个副作用会向下停止。理想情况下,这种过渡是顺利的,但我很难找到一种方法来做到这一点。我再次意识到滚动视图内部的滚动视图并不理想,但如果我能解决这个小问题,一切都会很好,而不是试图重新设计整个事物。

关于如何处理双滚动的任何想法,让平移手势获胜,但当外部滚动视图不能再垂直平移时,干净地过渡到内部集合?

1 个答案:

答案 0 :(得分:2)

所以,既然我没有得到任何答案,这就是我一直在使用的解决方案。基本上,如果内部集合视图不在顶部或底部,我重置外部滚动视图在scrollViewDidScroll中的y偏移更改。代码如下所示:

- (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;
    }
}

使用这两种便利:

- (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;
}

你需要2个类变量,一个浮点数来保存外部滚动的前一个y内容偏移量,还有一个BOOL来保存是否要允许外部滚动视图滚动,你可以设置为YES缩放或以编程方式滚动。这个解决方案修复了双滚动,但是在scrollviewDidScroll中有一个麻烦的黑客,可能会在以后咬你,你经常需要解决,但是现在这是我一直在使用的解决方案。