如何在UIScrollView中识别滑动手势

28

我正在尝试识别UIScrollView中的左/右滑手势。 我尝试创建UISwipeGestureRecognizers并将它们与滚动视图关联,这样做有时会起作用,但大部分时间不会被调用。为什么?

如何可靠地实现向左/右滑动? 我可以使用手势识别器吗?还是必须在touchesBegan/Ended中自己处理?

谢谢

4个回答

42
我找到了解决方法。在我的情况下,我的UIScrollView包含了一张我允许缩放的UIImage。显然这意味着滚动是启用的,UIScrollView难以区分旨在滚动还是划动(下一张、上一张图片)的手势。
关键在于当图像没有被缩放时,禁用滚动视图中的滚动功能,并在图像被缩放时重新启用它。这样就实现了预期的行为。
关键部分是将以下内容放置在scroll view的代理中:
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
  if (scrollView.zoomScale!=1.0) {
    // Zooming, enable scrolling
    scrollView.scrollEnabled = TRUE;
  } else {
    // Not zoomed, disable scrolling so gestures get used instead
    scrollView.scrollEnabled = FALSE;
  }
}

我还需要在滚动视图中禁用滚动并进行初始化。 要启用缩放,只需在委托调用上提供一个图像即可。

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
  // Return the scroll view
  return myImage;
}

在viewDidLoad中设置一些参数以进行缩放并设置手势识别器

- (void)viewDidLoad {
  [super viewDidLoad];
  myScrollView.contentSize = CGSizeMake(myImage.frame.size.width, myImage.frame.size.height);
  myScrollView.maximumZoomScale = 4.0;
  myScrollView.minimumZoomScale = 1.0;
  myScrollView.clipsToBounds = YES;
  myScrollView.delegate = self;

  [myScrollView addSubview:myImage];
  [self setWantsFullScreenLayout:TRUE];

  myScrollView.scrollEnabled = FALSE; 
  UISwipeGestureRecognizer *recognizer = 
    [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeFrom:)];
  recognizer.delaysTouchesBegan = TRUE;
  [myScrollView addGestureRecognizer:recognizer];
  [recognizer release];

  recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeFrom:)];
  recognizer.direction = UISwipeGestureRecognizerDirectionLeft;
  [myScrollView addGestureRecognizer:recognizer];
  [recognizer release];
  [myScrollView delaysContentTouches];
}

1
真是太棒了,David。我的滑动识别器也无法工作。我放弃了并使用了touchesBegan:with NSNotification,但它也会在iPad上为MasterViewControllers提供通知。我对寻找这个问题感到非常困惑。你节省了我的时间和精力!由衷感谢David。继续发布技巧...祝你有美好的一天。 - gopikrishnan
或者用一行代码表达 - scrollView.scrollEnabled = (scale != 1.0f) - Yariv Nissim
谢谢!我有一个小建议,因为我在横向模式下遇到了一些问题。我通过将scrollViewDidZoom方法更改为以下内容来绕过这些问题: '- (void)scrollViewDidZoom:(UIScrollView *)scrollView { if (scrollView.zoomScale!=self.scrollview.minimumZoomScale) { // Zooming, enable scrolling scrollView.scrollEnabled = TRUE; } else { // Not zoomed, disable scrolling so gestures get used instead scrollView.scrollEnabled = FALSE; } }' - johnnelm9r
1
使用 requireGestureRecognizerToFail 的新答案更容易。 - Daniel

36
UIScrollView *scrollView = ...
UISwipeGestureRecognizer *mySwipe = ...

解决此问题的正确方法是添加一行代码:

[scrollView.panGestureRecognizer requireGestureRecognizerToFail:mySwipe]

Swift版本:

scrollView.panGestureRecognizer.requireGestureRecognizerToFail(mySwipe)

Swift4 版本:

scrollView.panGestureRecognizer.require(toFail: mySwipe!);

绝对同意这是正确的解决方案!我还必须在同一行中添加pinchGestureRecognizer,以使其可靠,因为我正在尝试检测多指滑动。 - Luke Rogers
这绝对是正确的方式!有时我发现滑动手势触发有点太早了,但那是一个滑动处理程序的问题。至少我们不必去做其他人建议的各种奇怪的hacky事情,而仅仅“感觉不对”。谢谢!! - horseshoe7
1
有史以来最好的答案... :) - Ankit Kumar
1
这难道不会简单地破坏滑动手势方向上的滚动视图的平移手势吗?至少,我似乎不能让滑动手势失败。如果你想要在缩放的图像中拖动平移,同时又想要滑动浏览图片,该怎么办呢?即使它可能有些“hacky”,被接受的解决方案似乎更好。 - nickjwallin
@nickjwallin 不是。 - Alexander Volkov

4

好的文章。

我正在做类似的事情(没有图像视图),如果内容大小小于高度(我的滚动视图只竖向滚动),我基本上必须禁用滚动。

if (scrollView.contentSize.height>scrollView.frame.size.height) {
    scrollView.scrollEnabled = YES;
}
else {
    scrollView.scrollEnabled = NO;
}

那对我来说起作用了。

1
对于那些想要动画化和自定义滑动手势识别器的人。
我们可以使用UIScrollView和UIGestureRecognizer代理:
 Class ViewController: UIViewController, UISCrollViewDelegate, UIGestureRecognizerDelegate { 


   override func viewDidLoad() {
    super.viewDidLoad()

    scrollView.delegate = self
    swipeLeft.delegate = self
    swipeRight.delegate = self

  }


  func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    return true
  }

  func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
  }

  func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    return scrollView.alwaysBounceHorizontal
  }


  func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {

    // Your custom animation at the end of scrolling.
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接