Override UIGestureRecognizer touchesBegan
Ôh ! Here is the Swift code for nextResponder :
https://stackoverflow.com/a/26510277/4135158
Overriding touchesBegan: Error - method does not override any method from superclass
I was indeed using Xcode 7.2 with Swift 2.0. And removing the override keyboard was not the solution. Instead, I found that the solution was to add import UIKit.UIGestureRecognizerSubclass. That also allowed me to write over the state property, rather than it being read-only.
touchesBegan Vs UITapGestureRecognizer
so if you hold on the red square for two seconds you'll get a message, when you let go the message disappears. you might have to add some booleans in there to make sure your character isnt repeating some action every frame after the 2 second button hold. this should be enough to get you started hopefully
import SpriteKit
class GameScene: SKScene {
// time values
var delta = NSTimeInterval(0)
var last_update_time = NSTimeInterval(0)
var longTouchTimer = NSTimeInterval(0)
var touched = false
var testLabel = SKLabelNode(text: "you have touched for awhile now bro")
let touchSprite = SKSpriteNode(color: SKColor.redColor(), size: CGSizeMake(100, 100))
override func didMoveToView(view: SKView) {
touchSprite.position = CGPointMake(self.size.width/2, self.size.height/2)
addChild(touchSprite)
testLabel.hidden = true
testLabel.position = touchSprite.position
testLabel.position.y += 100
testLabel.fontSize = 20
addChild(testLabel)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if touchSprite.containsPoint(location) {
touched = true
}
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if !touchSprite.containsPoint(location) {
touched = false
longTouchTimer = 0
}
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
touched = false
longTouchTimer = 0
}
override func update(currentTime: NSTimeInterval) {
if last_update_time == 0.0 {
delta = 0
} else {
delta = currentTime - last_update_time
}
last_update_time = currentTime
if touched {
longTouchTimer += delta
}
if longTouchTimer >= 2 {
testLabel.hidden = false
} else {
testLabel.hidden = true
}
}
}
How to replace TouchesBegan with UIGestureRecognizer
For what you are tryin ti do you can't. The gesture recoginizers are for high level gestures so they behaive the same across all apps (think swipes, the timing required for a double tap, etc). For low level control and to do things that the recognizers can't you will still have to implement logic in touchesbegan, touchesEnded, etc.
UIGestureRecognizer subclass-- touchesMoved automatically changes state to .changed
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)
}
}
UIPanGestureRecognizer does not have a member named touchesBegan
You don't have to override the functions, you can just define them like below. But I am not exactly sure why that is. In a custom UIView
these functions have to be overridden.
func touchesBegan(touches: NSSet!, withEvent event: UIEvent!) {
println("here")
}
func touchesMoved(touches: NSSet!, withEvent event: UIEvent!) {
}
func touchesEnded(touches: NSSet!, withEvent event: UIEvent!) {
}
func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) {
}
UIView touchesBegan won't fire when UILongPressGestureRecognizer minimumPressDuration zero
Despite the misuse of UILongPressGestureRecognizer
for a scenario where UITapGestureRecognizer
has to be used instead, I will focus on answering the "why" part.
When you set gesture.minimumPressDuration = .zero
, the long-press gesture gets instantly recognized.
By default, gesture recognizers tend to delay touches in view, and cancel them if they recognize the gesture.
In order to override this behavior, set
gesture.cancelsTouchesInView = false // to recieve touchesBegan callback even if gesture is recognized
gesture.delaysTouchesBegan = false // to not delay touchesBegan callback
gesture.delaysTouchesEnded = false // to not delay touchesEnded callback
Related Topics
Why How to Make Same-Type Requirement in Swift with Generics? Is There Any Way
Iocreateplugininterfaceforservice Returns Mysterious Error
Type 'Bundle' Has No Member "Module"
Sizing a UIpickerview Inside a UIalertview
Make Tabview Background Transparent
Save/Copy a File from Bundle to Desktop Using Nssavepanel
Uitableview Only Displays One Section
Getting Common Data from Two Different Types of Array
How to Unwrap Optional<Optional<T>> in Swift 1.2
"'Init' Is Deprecated" Warning After Swift4 Convert
How to Use The Delegates with Nskeyedunarchiver
Convert Single File to Swift 3 in Xcode 8
Swift iOS14 Datepicker Text Alignment
Swift Increment Int! Not Working
Detecting Swipes on All Four Directions on Watchkit Using The Storyboard
Nsmanagedobjectcontext's Propagatesdeletesatendofevent Set to False Causes Error on Save