Ios 自定义UIGestureRecognitor并不总是调用其操作方法
我有一个自定义的UIGestureRecognitor,它可以正确识别所需的手势(2个手指的Z手势),并在Ios 自定义UIGestureRecognitor并不总是调用其操作方法,ios,swift,uigesturerecognizer,Ios,Swift,Uigesturerecognizer,我有一个自定义的UIGestureRecognitor,它可以正确识别所需的手势(2个手指的Z手势),并在touchesEnded中设置状态=.Recognited。问题是,即使手势被识别,它有时调用动作方法,有时不调用。据我所知,这是不确定的 有人知道为什么吗 代码如下: import UIKit import UIKit.UIGestureRecognizerSubclass class ZGestureRecognizer: UIGestureRecognizer { priv
touchesEnded
中设置状态=.Recognited
。问题是,即使手势被识别,它有时调用动作方法,有时不调用。据我所知,这是不确定的
有人知道为什么吗
代码如下:
import UIKit
import UIKit.UIGestureRecognizerSubclass
class ZGestureRecognizer: UIGestureRecognizer {
private var topSwipeStartPoint = CGPoint.zero
private var diagonalSwipeStartPoint = CGPoint.zero
private var bottomSwipeStartPoint = CGPoint.zero
private let minDeltaX: CGFloat = 20
private let minDeltaY: CGFloat = 20
private var strokePhase = StrokePhase.notStarted
var trackedTouch: UITouch?
enum StrokePhase {
case notStarted
case topSwipe
case diagonalSwipe
case bottomSwipe
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
if !(touches.count == 1 || touches.count == 2) {
state = .failed
return
}
if trackedTouch == nil {
trackedTouch = touches.min { $0.location(in: self.view?.window).x < $1.location(in: self.view?.window).x }
strokePhase = .topSwipe
topSwipeStartPoint = trackedTouch!.locationInWindow!
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
guard let trackedTouch = trackedTouch,
trackedTouch.phase != .cancelled,
trackedTouch.phase != .ended
else {
self.state = .failed
return
}
let newPoint = trackedTouch.locationInWindow!
let previousPoint = trackedTouch.previousLocationInWindow!
switch strokePhase {
case .topSwipe:
if newPoint.x < previousPoint.x { // if we have started moving back to the left
let deltaX = previousPoint.x - topSwipeStartPoint.x
if deltaX > minDeltaX && touches.count == 2 {
diagonalSwipeStartPoint = previousPoint
strokePhase = .diagonalSwipe
}
else { // too short right swipe or not 2 touches
state = .failed
return
}
}
case .diagonalSwipe:
if newPoint.x > previousPoint.x { // if we have started moving back to the right
let deltaX = diagonalSwipeStartPoint.x - previousPoint.x
let deltaY = previousPoint.y - diagonalSwipeStartPoint.y
if deltaX > minDeltaX && deltaY > minDeltaY && touches.count == 2 {
bottomSwipeStartPoint = previousPoint
strokePhase = .bottomSwipe
}
else { // too short right swipe
state = .failed
return
}
}
case .bottomSwipe:
if newPoint.x < previousPoint.x || touches.count != 2 {
state = .failed
return
}
default: break
}
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) {
state = .failed
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
guard strokePhase == .bottomSwipe else {
state = .failed
return
}
let endPoint = trackedTouch!.locationInWindow!
let bottomSwipeDeltaX = endPoint.x - bottomSwipeStartPoint.x
if bottomSwipeDeltaX > minDeltaX {
state = .recognized
}
else {
state = .failed
}
}
override func reset() {
strokePhase = .notStarted
trackedTouch = nil
}
}
导入UIKit
导入UIKit.UIgestureRecognitizerSubclass
类ZgestureRecognitor:UIgestureRecognitor{
私有变量topSwipeStartPoint=CGPoint.zero
私有变量对角swipestartpoint=CGPoint.zero
私有变量bottomSwipeStartPoint=CGPoint.zero
私人出租minDeltaX:CGFloat=20
私人出租minDeltaY:CGFloat=20
私有变量strokePhase=strokePhase.notStarted
var trackedTouch:UITouch?
枚举冲程相位{
案例未开始
箱子上擦布
格斜击
箱底刷
}
覆盖func touchesStart(touchs:Set,带有事件:UIEvent){
如果!(touchs.count==1 | | touchs.count==2){
状态=。失败
返回
}
如果trackedTouch==nil{
trackedTouch=touchs.min{$0.location(在:self.view?窗口中).x<$1.location(在:self.view?窗口中).x}
冲程相位=.topSwipe
TopsweepStartPoint=trackedTouch!.locationInWindow!
}
}
覆盖func touchesMoved(touches:Set,带有event:UIEvent){
guard let trackedTouch=trackedTouch,
trackedTouch.phase!=已取消,
trackedTouch.phase!=结束
否则{
self.state=.failed
返回
}
让newPoint=trackedTouch.locationInWindow!
让previousPoint=trackedTouch.previousLocationInWindow!
开关冲程相位{
案例1.1:
如果newPoint.xminDeltaX&&Touchs.count==2{
对角点=上一点
strokePhase=.对角线滑动
}
否则{//太短,右击或不触2下
状态=。失败
返回
}
}
案例。对角滑动:
如果newPoint.x>previousPoint.x{//如果我们已经开始往右移动
设deltaX=对角swipestartpoint.x-上一个点.x
设deltaY=previousPoint.y-对角线swipestartpoint.y
如果deltaX>minDeltaX&&deltaY>minDeltaY&&Touchs.count==2{
bottomSwipeStartPoint=上一个点
strokePhase=.bottomSwipe
}
else{//右击太短
状态=。失败
返回
}
}
案例。底部滑动:
如果newPoint.xminDeltaX{
状态=。已识别
}
否则{
状态=。失败
}
}
重写函数重置(){
strokePhase=.notStarted
跟踪触摸=零
}
}
由于手势识别总是以行
state=.recognized
结尾,所以在做适当的手势时,我认为代码不相关,但我很乐意出错。我模拟了您的代码。我无法得到正确的手势(您没有提到所需的手势)。因此,在我的例子中,state=.recognized从未执行过。然后,我硬编码了touchesend中的state=.recognized,以检查是否每次设置state=.recognized时都调用了action方法。我觉得很好
我发现所有被重写的方法都缺少超级调用。您可以拨打所有超级电话,然后再次检查。此外,将一个日志放在日志中。我认为可能有一个逻辑问题。因为,我不知道触发它所需的手势,我无法调试代码。我猜您在这个应用程序中编写了一些代码?或者你想让我们想象一下你写了什么?问题是状态设置为。每次执行手势时都会被识别,但动作目标并不是每次都被调用,那么代码的其余部分是如何相关的?据我所知,设置state=.recognized应该会触发目标操作。您是否确定在成功执行手势时(例如,通过在其中添加日志语句),始终会到达将
state
设置为recognized
的代码路径?需要考虑的其他事项:您从未将状态设置为其他生命周期状态(可能的,开始的,更改的,…)。子类化()的文档建议始终在可能的
状态下启动。是的,我已经检查了每次成功执行手势时执行是否达到状态=。已识别
。如果我正确理解了文档,则状态开始
和更改
与连续手势识别器一起使用——我的是离散手势识别器。此外,根据文档,UIKit会在手势失败或成功后将状态设置回可能
。一种离散手势识别器