ios - 同一 View (从可 ScrollView 中拖动 View )上的多个手势无法正常工作?

标签 ios swift uigesturerecognizer uipangesturerecognizer

为了让我的panGesture(附加到UIImageView)被调用,我需要确保用户没有在图像所在的水平ScrollView中滚动。我是这样实现的:

let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.handlePan(_:)))
    panGesture.require(toFail: self.scrollView.panGestureRecognizer)

这很好用,但是因为scrollView仅是水平,所以它仅允许panGesture水平工作。我也想垂直拉UIImage,但是什么也没有发生,因为显然,只有在滚动视图失败(只能水平失败)时才调用它。

有什么方法可以确保上面的方法有效,但无论如何,都可以将panGesture垂直称为

最佳答案

好的,我结合了几件事解决了这个问题。看起来要添加很多东西,但是在其他项目中会派上用场。

步骤1:启用水平滚动UIScrollView以使水平均“失败”。

尽管我只希望UIScrollView水平滚动,但仍需要垂直滚动,以便失败(即将推出)。失败使我能够将子视图UIScrollView中“拉出”。
scrollView本身的高度是40,因此它的contentSize必须具有更大的高度才能使其仅能垂直滚动。

self.effectTotalHeight.constant = 41
self.scrollView.contentSize = CGSize(width: contentWidth, height: self.effectTotalHeight.constant)

大!它垂直滚动。但是现在内容是橡皮筋(我们不想要)。反对别人这么说,不要便宜,只是禁用反弹。 (特别是如果您想在水平滚动时弹跳!)

注意:我还意识到只有在StoryBoard中禁用Bounce Horizontally才能...嗯,什么都没有(错误?)。

步骤2:UIScrollViewDelegate添加到View Controller类中并检测滚动

现在,我要检测滚动并确保垂直滚动时,它实际上并未滚动。为此,即使正在滚动,contentOffset.y位置也不应更改。 UIScrollViewDelegate提供了一个委托函数scrollViewDidScroll,在滚动时会被调用。只需将其设置为:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
    scrollView.contentOffset.y = 0.0
}

为了调用此方法,还需要将scrollView的委托设置为self:
self.scrollView.delegate = self

请记住,此控件可控制和所有 UIScrollView,因此如果您希望仅影响特定语句,请提供if语句或switch语句。就我而言,这个视图控制器只有一个UIScrollView,所以我什么也没放。

好极了!因此,现在它仅再次水平滚动,但是此方法仅将contentOffset.y保持在0。它不会使它失败。我们确实需要这样做,因为scrollView垂直失败是启用平移手势识别器(使您能够拖动和拖动等)的关键。因此,让它失败吧!

步骤3:覆盖UIScrollView默认手势识别

为了覆盖任何默认手势识别器,我们需要将UIGestureRecognizerDelegate作为另一个委托方法添加到View Controller类。
scrollView现在需要其自己的平移手势识别器处理程序,以便我们可以检测其上的手势。您还需要将新scrollGesture的委托设置为self,以便我们可以检测到它:
let scrollGesture = UIPanGestureRecognizer(target: self, action: #selector(self.handleScroll(_:)))
    scrollGesture.delegate = self
self.scrollView.addGestureRecognizer(scrollGesture)

设置handleScroll函数:
func handleScroll(_ recognizer: UIPanGestureRecognizer) {
    // code here
}

一切都很好,但是为什么我们要全部设置呢?记住,我们禁用了contentOffset.y,但是垂直滚动不是而不是。现在,我们需要检测滚动的方向,并使其垂直滚动失败,以便激活panHandle

步骤4:检测手势方向并使其失败(失败是好的!)

我扩展了UIPanGestureRecognizer,以便通过进行以下 public 扩展来检测并发出方向:
public enum Direction: Int {
   case Up
   case Down
   case Left
   case Right

   public var isX: Bool { return self == .Left || self == .Right }
   public var isY: Bool { return !isX }
}

public extension UIPanGestureRecognizer {
  public var direction: Direction? {
      let velo = velocity(in: view)
      let vertical = fabs(velo.y) > fabs(velo.x)
      switch (vertical, velo.x, velo.y) {
         case (true, _, let y) where y < 0: return .Up
         case (true, _, let y) where y > 0: return .Down
         case (false, let x, _) where x > 0: return .Right
         case (false, let x, _) where x < 0: return .Left
         default: return nil
      }
   }
}

现在,为了正确使用它,您可以在recognizer函数内部获取.directionhandleScroll并检测发出的方向。在这种情况下,我要查找.Up.Down,并希望它向发出失败的。我们通过禁用识别器来做到这一点,然后在之后立即重新启用它:
func handleScroll(_ recognizer: UIPanGestureRecognizer) {
    if (recognizer.direction == .Up || recognizer.direction == .Down) {
        recognizer.isEnabled = false
        recognizer.isEnabled = true
    }
}

之所以将.isEnabled立即设置为true的原因是因为false发出失败的,从而启用另一个手势(“拉出”(平移)其内部视图),但不会永远被禁用(否则它将停止)被称为)。通过将其设置回false,它可以在发出失败后立即重新启用此侦听器。

步骤5:通过相互覆盖使多个手势起作用

最后但并非最不重要的一点是,这是非常重要的一步,因为它允许平移手势和滚动手势独立工作,并且没有一个总是总是覆盖另一个。
func gestureRecognizer(_: UIGestureRecognizer,
    shouldRecognizeSimultaneouslyWith shouldRecognizeSimultaneouslyWithGestureRecognizer:UIGestureRecognizer) -> Bool {
    return true
}

就是这样!这是关于SO(主要是找到不起作用的东西)和实验的大量研究,但都融合在一起。

编写此文档时,期望您已经为要“拉出”的滚动视图内的对象以及如何处理其状态(true.ended等)编写了平移手势识别器。我建议如果您需要帮助,请搜索。有很多答案。

如果您对此答案还有其他疑问,请告诉我。

关于ios - 同一 View (从可 ScrollView 中拖动 View )上的多个手势无法正常工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42755636/

相关文章:

ios - 回调中的类型推断错误

ios - 在 UITextField 下放置一行的正确方法是什么

ios - 通过子类化在文本字段前添加空格

ios - 在 TableView 上检测滑动手势

ios - 从当前比例捏合/缩放

ios - Pod 更新后编译 Swift 3.0.1 项目时出错

ios - 无法从 plist 获取内容到 UITableview

ios - Swift 不检索 Firebase 值(返回值作为 NSNull)

swift - 在 ViewController 中处理菜单项操作

ios - 添加滑动手势以在详细 View 中显示下一个项目