UILongTapGestureRecognizer

UILongTapGestureRecognizer

我需要同时使用UILongTapGestureRecognizerUIPinchGestureRecognizer

不幸的是,UILongTapGestureRecognizer的第一次触摸也会被计为PinchGestureRecognizer。因此,在按住UILongTapGestureRecognizer时,只需再触摸一下即可触发Pinch Recognizer。一种用于长按手势,另一种用于捏合。

有没有办法单独使用两者?我不想将UILongTapGestureRecognizer用作我的UIPinchGestureRecognizer

这就是我启用同时工作人员的方式:

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

    //Allowing
    if (gestureRecognizer == zoom) && (otherGestureRecognizer == longTap) {
        print("working while filming")
        return true
    }

    return false
}

最佳答案

我认为您没有想要的工具,因此建议您尝试创建自己的手势识别器。并不是真的那么难,但是不幸的是,您需要同时进行长按和捏合效果。

不要尝试覆盖UIPinchGestureRecognizerUILongPressGestureRecognizer,因为它根本行不通(或者,如果要管理,请分享您的发现)。因此,直接进入UIGestureRecognizer

因此,从长按手势识别器开始,我们需要跟踪用户按下并保持足够长的时间而不会移动太多。因此,我们有:

var minimumPressDuration = UILongPressGestureRecognizer().minimumPressDuration
var allowableMovement = UILongPressGestureRecognizer().allowableMovement

现在需要覆盖触摸(所有这些都在手势识别器的子类中):
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
    touchMoveDistance = 0.0 // Reset the movement to zero
    previousLocation = touches.first?.location(in: view) // We need to save the previous location
    longPressTimer = Timer.scheduledTimer(timeInterval: minimumPressDuration, target: self, selector: #selector(onTimer), userInfo: nil, repeats: false) // Initiate a none-repeating timer
    if inProgress == false { // inProgress will return true when stati is either .began or .changed
        super.touchesBegan(touches, with: event)
    }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
    if let newLocation = touches.first?.location(in: view), let previousLocation = previousLocation {
        self.previousLocation = newLocation
        touchMoveDistance += abs(previousLocation.y-newLocation.y) + abs(previousLocation.x-newLocation.x) // Don't worry about precision of this. We can't know the path between the 2 points anyway
    }
    if inProgress == false {
        super.touchesMoved(touches, with: event)
    }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
    longPressTimer?.invalidate()
    longPressTimer = nil
    if inProgress {
        state = .ended
    }
    super.touchesEnded(touches, with: event)

    if self.isEnabled { // This will simply reset the gesture
        self.isEnabled = false
        self.isEnabled = true
    }
}

override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) {
    longPressTimer?.invalidate()
    longPressTimer = nil
    if inProgress {
        state = .ended
    }
    super.touchesCancelled(touches, with: event)

    if self.isEnabled {
        self.isEnabled = false
        self.isEnabled = true
    }
}

因此,所有这些仅用于长按。在计时器上发生的是:
@objc private func onTimer() {
    longPressTimer?.invalidate()
    longPressTimer = nil
    if state == .possible {
        state = .began
    }
}

因此,基本上,如果我们将状态更改为.begin,我们将触发手势,其余事件将正常工作。这很整洁。

不幸的是,这还远远没有结束,您将需要对其余的代码进行一些操作...

您将需要保留触摸(如果我没记错的话,相同的触摸将被报告为可比较的对象,直到用户抬起手指为止):
  • 在开始时,将触摸保存到 private 属性longPressTouch
  • 长按成功后在计时器上设置属性以指示长按确实触发了didSucceedLongPress = true
  • 在开始时,请检查是否可以添加另一触摸,如果不能,请取消手势if longPressTouch != nil && didSucceedLongPress == false { cancel() }。还是允许它,这实际上取决于您想要什么。
  • 如果可以添加触摸,则在开始时将其添加到数组中并保存其初始位置。pinchTouches.append((touch: touch, initialPosition: touchPosition))
  • 触摸结束并取消时,请确保从数组中删除适当的触摸。如果取消长按,则取消该事件(或再次取消选择)

  • 因此,这应该是捏手势识别器所需的所有数据。由于所有事件应该已经按照您需要的方式为您触发了,所以您需要的是比例的计算值:
    var pinchScale: CGFloat {
        guard didSucceedLongPress, pinchTouches.count >= 2 else {
            return 1.0 // Not having enough data yet
        }
        return distanceBetween(pinchTouches[0].touch, pinchTouches[1].touch)/distanceBetween(pinchTouches[0].initialPosition, pinchTouches[1].initialPosition) // Shouldn't be too hard to make
    }
    

    然后,您需要检查一些边缘情况,例如:
    用户长按一次,用两根手指捏,加第三根手指(忽略),移开第二根手指:如果不进行此操作,您可能会略有跳动,这可能是故意的,也可能是故意的。我想您可以取消手势,也可以以某种方式转换初始值以使跳转消失。

    祝您好运,如果您将执行此操作,并告诉我们它的进展情况。

    09-25 18:45