我有两个嵌套的UIScrollViews,都在垂直方向滚动。在允许内部scrollview滚动之前,我需要外部scrollview首先滚动到它的最大范围。在外部scrollview达到其最大范围之前,内部scrollview不应该是可滚动的。这是一个例子:
在左图中,Scrollview B
内的垂直拖动应移动Scrollview A
,而Scrollview B
不应滚动(但仍需要能够接收触摸/点击)。一旦Scrollview A
达到最大范围(当Scrollview B
到达屏幕顶部时),则Scrollview B
应滚动。这需要一个连续的动作。
我试图从ScrollView B
的{{1}}委托方法切换scrollEnabled
的{{1}},但这似乎不是一个可行的解决方案,因为它在一个连续动作中不起作用(例如:用户需要在ScrollView A
到达屏幕顶部后再次释放和触摸)。
实现这一目标的最佳方式是什么,这是一个连续的运动?
答案 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
向同一方向滚动时,会发生相同的方向滚动。这显示在左图中。
只需设置上图中提到的一些属性即可。它有效。