我正在开发一个应用程序,其中有几个UIView对象是UIScrollView对象上的子视图。我以编程方式创建子视图,并根据关联对象的属性将它们放在滚动视图上。允许用户在滚动视图上移动这些子视图。通常这是有效的,但有时滚动视图会抓取平移手势。
我想做的是如果触摸位置在其中一个子视图内,则禁止滚动视图手势识别器。
我可以通过查看滚动视图的手势识别器数组并查找UIScrollViewPanGestureRecognizer
对象来找到滚动视图手势识别器。我假设只能有一个。
我的想法是让我的视图控制器成为这个手势识别器的代表,然后如果触摸位于其中一个子视图的范围内,则让代理禁止它。
这是处理这种情况的最佳方式,还是有更好的方法?
我做过类似的事情,在我对这个问题的回答中有所描述。 How to get stepper and longpress to coexist?
嗯。看起来比我预想的更难识别scrollview的UIScrollViewPanGestureRecognizer
。任何有关这样做的提示都将受到赞赏。
我的想法不起作用。为了编码我的想法,我不得不让我的VC成为scrollview的pan手势识别器的代表。但是,当我这样做时,我收到了这个错误:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'UIScrollView's built-in pan gesture recognizer must have its scroll view as its delegate.'
这是我使用的代码。在viewDidLoad
中,我调用了一个获取scrollview的平移手势识别器并将self设置为委托的方法(self.scrollViewPanGestureRecognizer
只是存储它的属性):
self.scrollViewPanGestureRecognizer = [self.scrollView panGestureRecognizer];
self.scrollViewPanGestureRecognizer.delegate = self;
然后我实现了这个委托方法:
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
//Disable touch if touch location is in a subview.
BOOL enableGestureRecognizer = YES;
if (gestureRecognizer == self.scrollViewPanGestureRecognizer) {
CGPoint touchLocation = [touch locationInView:self.scrollView];
for (UIView *s in self.scrollView.subviews) {
if (CGRectContainsPoint(s.frame, touchLocation)) {
enableGestureRecognizer = NO;
}
}
}
return enableGestureRecognizer;
}
看起来像个好主意,但看起来我不能让我的VC成为代表。
刚刚尝试在滚动视图中将scrollEnabled
设置为NO
。这成功禁用了滚动,但它没有解决问题。视图仍然偶尔不响应手势。想到可能有些错误导致手势识别器从对象上掉下来,我让调试器显示有问题视图的手势识别器。他们还在那里。我很难过。
更新:新信息。我终于意识到没有响应的子视图是屏幕右侧的子视图。仔细测试后,似乎只在横向方向上发生这种情况,并且只有当手指位置在portraite的右边缘右侧时,即320点。显然,当旋转到风景时,某些东西不被处理。一切看似正常,但手势无法识别。
只是为了笑,我决定在方法viewDidLayoutSubviews
中显示帧和边界以及内容区域。我得到的是:
self.view.frame is {{0, 0}, {480, 320}}
self.view.bounds is {{0, 0}, {480, 320}}
self.scrollView.frame is {{0, 0}, {480, 320}}
self.scrollView.bounds is {{0, 0}, {480, 320}}
self.scrollView.contentSize is {480, 320}
我似乎错过了一些东西。旋转时还需要设置什么?
答案 0 :(得分:4)
使用requireGestureRecognizerToFail
:方法。
您希望滚动视图平移手势( scrollViewGesture )在其子视图上发生其中一个手势时失败。
因此,当您将pan手势添加到subView( subViewGesture )时,请将下面的属性设置为
scrollViewGesture.requireGestureRecognizerToFail =subViewGesture;
答案 1 :(得分:1)
我找到了解决方案。我忘记了子视图没有直接放在滚动视图中。最初占据子视图所在的scrollview边界的视图。层次结构如下:
self.view
scroll view
UIView (fills whole scroll view)
subview1
subview2
subviewn
在我处理旋转的代码中,我没有调整放置子视图的UIView的大小。纠正这个问题解决了这个问题。
我最初尝试将没有UIView超级视图的子视图放在它们和滚动视图之间,但由于某种原因它不起作用。添加这个额外的层解决了这个问题,但我忘了在旋转时处理调整大小。
所以我猜手势识别器没有回应,因为虽然它们是可见的,但它们超出了他们的超视范围。
答案 2 :(得分:0)
我正在将此答案作为社区维基,因为我还没有完全解决这个问题。主要的是从文档中利用这一点:
子类可以覆盖
touchesShouldBegin:withEvent:inContentView:
,pagingEnabled
和。{touchesShouldCancelInContentView:
方法(由...调用) 滚动视图)以影响滚动视图如何处理滚动 手势。
答案 3 :(得分:-1)
一种解决方案:不要使用手势识别器,只需禁用所有这些功能,然后直接使用touchesBegan
,touchesMove
和touchesEnded
。这可能有点工作,但很确定它会按照你想要的方式工作。
您需要在子视图上禁用用户互动,禁用滚动视图上的滚动,并直接修改滚动视图的contentOffset
。