处理嵌套UIScrollViews向同一方向滚动的触摸

时间:2014-12-12 19:47:20

标签: ios iphone uitableview uiscrollview scroll

我有两个嵌套的UIScrollViews,都在垂直方向滚动。在允许内部scrollview滚动之前,我需要外部scrollview首先滚动到它的最大范围。在外部scrollview达到其最大范围之前,内部scrollview不应该是可滚动的。这是一个例子: Nested Scrollviews Diagram

在左图中,Scrollview B内的垂直拖动应移动Scrollview A,而Scrollview B不应滚动(但仍需要能够接收触摸/点击)。一旦Scrollview A达到最大范围(当Scrollview B到达屏幕顶部时),则Scrollview B应滚动。这需要一个连续的动作。

我试图从ScrollView B的{​​{1}}委托方法切换scrollEnabled的{​​{1}},但这似乎不是一个可行的解决方案,因为它在一个连续动作中不起作用(例如:用户需要在ScrollView A到达屏幕顶部后再次释放和触摸)。

实现这一目标的最佳方式是什么,这是一个连续的运动?

5 个答案:

答案 0 :(得分:4)

我用以下方式解决了这个问题。我对此并不满意,因为它看起来太复杂了,但是它有效(请注意下面的代码是我的代码的简化版本,这是由于不同的UI更复杂):

我有3个控制滚动的属性:

@property (nonatomic, assign) CGFloat currentPanY;
@property (nonatomic, assign) BOOL    scrollA;
@property (nonatomic, assign) BOOL    scrollB;

两步滚动:

禁用B的滚动,并启用A的滚动。
这允许滚动A.

当A到达其最大位置时,禁用A的滚动,并启用滚动B:

-(void)scrollViewDidScroll: (UIScrollView *)scrollView {
    if (scrollView.contentOffset.y >= self.maxScrollUpOffset) {
        [scrollView setContentOffset:CGPointMake(0, self.maxScrollUpOffset) animated:NO];        
        self.scrollviewA.scrollEnabled = NO;
        self.scrollviewB.scrollEnabled = YES;
        self.scrollB = YES;
    }
}

这产生以下效果:
当A向上滚动时,它将在达到其最大尺寸时停止滚动。然而,B将不会开始滚动,因为A的平移手势识别器不将其动作转发到B的平移手势识别器。因此,必须抬起手指并开始第二次滚动。然后,B将滚动。这给出了两步滚动。

连续滚动:

对于连续滚动,B必须滚动,而开始滚动A的手指继续向上移动。为了检测这一点,我添加了另一个平移手势识别器,并使其能够使用A和B的内置手势识别器同时检测手势:

 - (BOOL)gestureRecognizer:(UIPanGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UISwipeGestureRecognizer *)otherGestureRecognizer {
    return YES;
}

在这个额外的平移手势识别器的动作中,我计算了在达到A的滚动限制之后手指向上移动的距离。通过该距离,然后以编程方式滚动B:

- (void)panGestureRecognizerAction:(UIPanGestureRecognizer *)recognizer {
    if (recognizer.state != UIGestureRecognizerStateChanged) {
        self.currentPanY = 0;
        self.scrollB = NO;
        self.scrollA = NO;
    } else {
        CGPoint currentTranslation = [recognizer translationInView:self.scrollviewA];
        CGFloat currentYup = currentTranslation.y;

        if (self.scrollA || self.scrollB) {
            if (self.currentPanY == 0) {
                self.currentPanY = currentYup;
            }

            CGFloat additionalYup = self.currentPanY - currentYup;
            if (self.scrollA) {
                CGFloat offset = self.scrollviewA.scrollUpOffset + additionalYup;
                if (offset >= 0) {
                    self.scrollviewA.contentOffset = CGPointMake(0, offset);
                } else {
                    self.scrollviewA.contentOffset = CGPointZero;
                }
            } else if (self.scrollB){
                self.scrollviewB.contentOffset = CGPointMake(0, additionalYup);
            }
        }
    }
}  

还有一个缺点:
如果您开始滚动,抬起手指,让scrollView减速,它将表现得像2阶段滚动,因为额外的平移手势识别器将无法识别任何平移手势。

答案 1 :(得分:4)

在我的情况下,我解决了外部ScrollView的UIScrollView子类化。

class MYOuterScrollView: UIScrollView, UIGestureRecognizerDelegate {

override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
}

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {

    return true
}

}

答案 2 :(得分:3)

你的要求是这应该在一个连续的动作中起作用,这就得到了答案:你只需要使用一个UIScrollView,而不是两个。

如果您只有一个滚动视图,则可以通过覆盖滚动视图的layoutSubviews方法并重新调整其内容来执行您的魔法,以根据contentOffset的当前值执行视差效果。确保contentSize始终反映完整高度(如果需要,您甚至可以在layoutSubviews内更新contentSize)。

对于体系结构,请使用现有图表,然后将Scrollview B替换为View B.

答案 3 :(得分:1)

滚动视图A的手势识别器需要传递到手势识别器以滚动视图B以进行连续运动,我很确定这是不可能的。为什么不组合两个滚动视图的内容,然后你将有一个连续的动作。此代码将scrollView A和B的内容合并为A。

UIScrollView* scrollViewA = ...;
UIScrollView* scrollViewB = ...;
NSArray* subviews = scrollViewB.subviews;
for (int i = 0; i < subviews.count; i++)
{
    UIView* subview = [subviews objectAtIndex:i];
    CGRect frame = subview.frame;
    frame.origin.y += scrollViewA.contentSize.height;
    subview.frame = frame;
    [scrollViewA addSubview:subview];
}
CGSize size = scrollViewA.contentSize;
size.height += scrollViewB.contentSize.height;
scrollViewA.contentSize = size;

答案 4 :(得分:-1)

同向滚动

当作为UIScrollView的子视图的UIScrollView向同一方向滚动时,会发生相同的方向滚动。这显示在左图中。

如果想查看详细信息https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/UIScrollView_pg/NestedScrollViews/NestedScrollViews.html

,请点击此链接

enter image description here

只需设置上图中提到的一些属性即可。它有效。