简体   繁体   中英

UIGestureRecognizer subclass— touchesMoved automatically changes state to .changed

I am trying to create a UIGestureRecognizer subclass, and in touchesMoved I have no code, yet state is being set to .changed .

Does anyone know why this is happening? I need to be able to decide for myself when we are in the .changed state.

If I remove my touchesBegan function and never move to .began , this doesn't happen.

import UIKit.UIGestureRecognizerSubclass

class MyRecognizer: UIGestureRecognizer {

    private var refView: UIView? {
        return self.view?.window
    }


    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
       super.touchesBegan(touches, with: event)

       if touches.count != 1 {
            state = .failed
            return
        }

        guard let location = touches.first?.location(in: refView) else {
            self.state = .failed
            return
        }

       state = .began

    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
        // there is no code here!
    }

   //This is how I'm debugging state
   override var state: UIGestureRecognizerState {
      get { return super.state }
      set {
          super.state = newValue
          print("state = \(newValue.debugDescription)")
      }  
    }

}

extension UIGestureRecognizerState: CustomDebugStringConvertible {
    public var debugDescription: String {
        switch self {
        case .began: return "began"
        case .possible: return "possible"
        case .changed: return "changed"
        case .ended: return "ended"
        case .cancelled: return "cancelled"
        case .failed: return "failed"
        }
    }
}

Your testing approach is flawed. I tried this (this is my test app's complete code):

import UIKit
import UIKit.UIGestureRecognizerSubclass

class MyRecognizer: UIGestureRecognizer {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesBegan(touches, with: event)
        print(self.state.rawValue)
    }
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesMoved(touches, with: event)
        print(self.state.rawValue)
    }
}

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let g = MyRecognizer(target: self, action: #selector(grFired))
        self.view.addGestureRecognizer(g)
        // Do any additional setup after loading the view, typically from a nib.
    }

    @objc func grFired(_ g:UIGestureRecognizer) {
        print("here", g.state.rawValue)
    }

}

Then I dragged on the background view, to which the gesture recognizer is attached. My gesture recognizer never moved from the possible state.

Also note that your expectations may be incorrect ("I need to be able to decide for myself when we are in the .changed state"). The normal and correct behavior is that, having declared the state to be .began in touchesBegan , your touchesMoved will be called once with state .began and the gesture recognizer will immediately advance to .changed automatically. That is correct ; if this is continuous gesture, it cannot be the case that a moved event should come in while we are in .began state without our proceeding to .changed . Again, here's a test:

import UIKit
import UIKit.UIGestureRecognizerSubclass

class MyRecognizer: UIGestureRecognizer {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesBegan(touches, with: event)
        if touches.count != 1 {
            state = .failed
            return
        }
        print(self.state.rawValue)
        self.state = .began
    }
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesMoved(touches, with: event)
        print("moved", self.state.rawValue)
    }
}

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let g = MyRecognizer(target: self, action: #selector(grFired))
        self.view.addGestureRecognizer(g)
        // Do any additional setup after loading the view, typically from a nib.
    }

    @objc func grFired(_ g:UIGestureRecognizer) {
        print("here", g.state.rawValue)
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM