我需要同时使用UILongTapGestureRecognizer
和UIPinchGestureRecognizer
。
不幸的是,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
}
最佳答案
我认为您没有想要的工具,因此建议您尝试创建自己的手势识别器。并不是真的那么难,但是不幸的是,您需要同时进行长按和捏合效果。
不要尝试覆盖UIPinchGestureRecognizer
或UILongPressGestureRecognizer
,因为它根本行不通(或者,如果要管理,请分享您的发现)。因此,直接进入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
,我们将触发手势,其余事件将正常工作。这很整洁。不幸的是,这还远远没有结束,您将需要对其余的代码进行一些操作...
您将需要保留触摸(如果我没记错的话,相同的触摸将被报告为可比较的对象,直到用户抬起手指为止):
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
}
然后,您需要检查一些边缘情况,例如:
用户长按一次,用两根手指捏,加第三根手指(忽略),移开第二根手指:如果不进行此操作,您可能会略有跳动,这可能是故意的,也可能是故意的。我想您可以取消手势,也可以以某种方式转换初始值以使跳转消失。
祝您好运,如果您将执行此操作,并告诉我们它的进展情况。