在UIScrollView上平移对象

时间:2014-02-03 05:38:19

标签: ios uiscrollview uigesturerecognizer

我正在开发一个应用程序,其中有几个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}
我似乎错过了一些东西。旋转时还需要设置什么?

4 个答案:

答案 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)

一种解决方案:不要使用手势识别器,只需禁用所有这些功能,然后直接使用touchesBegantouchesMovetouchesEnded。这可能有点工作,但很确定它会按照你想要的方式工作。

您需要在子视图上禁用用户互动,禁用滚动视图上的滚动,并直接修改滚动视图的contentOffset