内部具有垂直UIScrollViews的水平UIScrollView – 如何在滚动外部水平视图时阻止滚动内部滚动视图?

无法找到解决方案。

我正在构建一个具有大滚动视图的应用程序,它具有分页(水平)。 在这个滚动视图中,有一个UIView网格,每个网格中都有一个UIScrollview,带有垂直滚动视图。

现在,重点是,当我分页我的’大’滚动视图时,有时触摸会卡在网格的UIViews中的一个小滚动视图中。

我不知道如何避免它 – 尝试使用hitTest但仍然无法找到答案。

希望我清楚……

谢谢你的帮助。

编辑:

这是更大的scrollview:

@implementation UIGridScrollView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; self.pagingEnabled; return self; } @end 

现在,在这个UIGridScroll View中,我添加了一个子视图这个视图:

 @implementation UINoteView { IBOutlet UIScrollView *_innerScrollView; // this scrollview frame is in the size of the all UINoteView } - (void)awakeFromNib { _innerScrollView.contentSize = CGSizeMake(_innerScrollView.frame.size.width, _innerScrollView.frame.size.height+50.0f); } @end 

分页效果很好,内部滚动视图效果很好,但是当我分页较大的音符视图时,我的手指“卡在”_innerScrollView中的次数太多了。

谢谢!

@stanislaw,我刚试过你在iPhone设备上建议的解决方案。

我看到你的问题。

您的代码确实可以防止偶尔滚动垂直视图,但我相信不是同步手势识别完成工作 – 注释您为内部视图提供的整个代码,并使用外部滚动视图的代码进行以下修改:

 @interface OuterHorizontalScrollView : UIScrollView ... @property (weak) InnerVerticalScrollView *currentActiveView; // Current inner vertical scroll view displayed. @end @implementation OuterHorizontalScrollView - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { if (self.currentActiveView.dragging == NO) { self.currentActiveView.scrollEnabled = NO; // The presence of this line does the job } return YES; } - (void)scrollViewDidEndDragging:(PlacesScrollView *)scrollView willDecelerate:(BOOL)decelerate { self.currentActiveView.scrollEnabled = YES; // This is very likely should be done for all subviews, not only a current. } @end 

您可以gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: UIScrollView并实现gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: ,允许滚动视图的内置panGestureRecognizer与另一个滚动视图的手势识别器同时识别。

例:

 //This is needed because the public UIScrollView headers //don't declare the UIGestureRecognizerDelegate protocol: @interface UIScrollView (GestureRecognition)  @end @interface MyScrollView : UIScrollView @end @implementation MyScrollView - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { if (gestureRecognizer == self.panGestureRecognizer) { return YES; } else if ([UIScrollView instancesRespondToSelector:@selector(gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:)]) { //Note: UIScrollView currently doesn't implement this method, but this may change... return [super gestureRecognizer:gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:otherGestureRecognizer]; } return NO; //the default } @end 

将此子类用于水平视图或所有垂直滚动视图都应该足够了。

在尝试以这种方式使用之后,您可能会发现您更喜欢默认行为。 允许两个视图同时滚动几乎总是导致意外的垂直滚动,同时向左和向右滑动,这可能是刺激性的(大多数人不做完美的水平滑动手势)。

我对您的设置有点困惑,但您可能需要查看-[UIScrollView setDelaysContentTouches:] 。 在处理嵌套滚动视图时,您可以使用它来添加一些优先级。

一旦我遇到这种情况,我就有以下工作要做到这一点。

从UIScrollView中对您的视图进行子类化,您可以使用它。 在您的情况下,我可以看到您的UINoteView不是UIScrollView的子类,从ScrollViewinheritance它并从此类中删除innerScrollView。

我是这样做的:

在垂直滚动视图中使用shouldRecognizeSimultaneouslyWithGestureRecognizer (感谢@omz!)和自定义滑动手势识别器(参见类似问题)

水平滚动UIScrollView与垂直平移手势 ),我有以下设置:

 @interface UIScrollView (GestureRecognition)  @end @interface OuterHorizontalScrollView : UIScrollView ... @property (weak) InnerVerticalScrollView *currentView; // Current inner vertical scroll view displayed. @end @implementation OuterHorizontalScrollView - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { if (self.currentActiveView.placeVerticalScrollView.dragging == NO) { self.currentActiveView.placeVerticalScrollView.scrollEnabled = NO; return YES; } else { return NO; } } @end @interface InnerVerticalScrollView : UIScrollView... @property UISwipeGestureRecognizer *swipeGestureRecognizer; @end @implementation InnerVerticalScrollView - (id)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { ... self.swipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeGesture:)]; self.swipeGestureRecognizer.direction = UISwipeGestureRecognizerDirectionDown | UISwipeGestureRecognizerDirectionUp; [self addGestureRecognizer:self.swipeGestureRecognizer]; } return self; } - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { if (gestureRecognizer == self.panGestureRecognizer && self.scrollEnabled == YES) { return YES; } else if (gestureRecognizer == self.swipeGestureRecognizer) { return YES; } else { self.scrollEnabled = NO; } return NO; } - (void)handleSwipeGesture:(UIGestureRecognizer *)sender { self.scrollEnabled = YES; } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; } 

这段代码有点hacky:它只允许滚动垂直滚动视图,只有当它们的自定义滑动手势被识别时(只有顶部或底部方向),所有其他手势都传递给外部滚动视图,而外部滚动视图只允许任何手势,如果没有人正在拖动内部滚动视图。

注意:滑动手势也适用于缓慢或微小的滑动并不明显,但确实如此(请参阅上面引用问题的评论)。

我觉得它可以更容易完成,也许我稍后会重构它。

无论如何,现在外部滚动工作完美 – 它水平滚动,没有任何偶尔的内部滚动视图垂直平移。

稍后更新:正如我之前所预料的那样,我的解决方案确实包含了不必要的代码:请参阅@burik的答案,而部分基于我的解决方案,它会从中获取这些内容。

我认为使用velocity来确定滚动方向是一种更好的方法:

 - (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer { CGPoint velocity = [gestureRecognizer velocityInView:gestureRecognizer.view]; return fabs(velocity.y) > 3 * fabs(velocity.x); }