处理嵌套UIScrollViews向同一方向滚动的触摸 [英] Handling touches for nested UIScrollViews scrolling in the same direction

查看:97
本文介绍了处理嵌套UIScrollViews向同一方向滚动的触摸的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have two nested UIScrollViews, both scrolling in the vertical direction. I need the outer scrollview to scroll to it's max range first before allowing the inner scrollview to scroll. The inner scrollview should not be scrollable until the outer scrollview has reached it's max range. Here's an illustration:

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

In the left diagram, a vertical drag inside of Scrollview B should move Scrollview A and Scrollview B should not be scrollable (but it still needs to be able to receive touches/taps). Once Scrollview A reaches it's max range (when Scrollview B gets to the top of the screen), then Scrollview B should scroll. This needs to work in one continuous motion.

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

I've attempted to toggle ScrollView B's scrollEnabled from ScrollView A's scrollViewDidScroll: delegate method, but this doesn't appear to be a viable solution because it doesn't work in one continuous motion (eg: The user needs to release and touch again after Scrollview B reaches the top of the screen).

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

What's the best way to implement this such that is works in one continuous motion?

推荐答案

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

I solved the problem in the following way. I am not really happy with it since it looks to me much too complicated, but it works (please note that the code below is a simplified, untested version of my code, which is due to a different UI more complicated):

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

I have 3 properties that control scrolling:

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

两步滚动:

禁用B的滚动,并启用A的滚动。

这允许滚动A。

Disable scrolling for B, and enable scrolling for A.
This allows to scroll A .

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

When A reaches its max position, disable scrolling for A, and enable scrolling for 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将滚动。这给出了两步滚动。

This gives the following effect:
When A is scrolled upwards it will stop scrolling when its max size is reached. However B will not start scrolling, since the pan gesture recognizer of A does not forward its actions to the pan gesture recognizer of B. Thus one has to lift the finger and to start a 2nd scrolling. Then, B will scroll. This gives the 2-step scrolling.

连续滚动:

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

For continuous scrolling, B must scroll while the finger that started scrolling of A continues moving upwards. To detect this, I added a further pan gesture recognizer tho A, and enabled it to detect gestures simultaneously with the built-in gesture recognizers of A and B:

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

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

In the action of this additional pan gesture recognizer, I compute the distance the finger has moved upwards after the scrolling limit of A has been reached. By this distance, B is then scrolled programmatically:

- (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阶段滚动,因为额外的平移手势识别器将无法识别任何平移手势。

There is still a disadvantage:
If you start scrolling, lift the finger, and let the scrollView decelerate, it will behave like the 2-stage scrolling, since the additional pan gesture recognizer won’t recognize any pan gesture.

这篇关于处理嵌套UIScrollViews向同一方向滚动的触摸的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆