Override UIGestureRecognizer touchesBegan - swift

I have 1 Main View and 1 SubView:
Main View > SubView
I think that the Main View is "stealing" the events from the SubView.
For example, when I tap on the SubView, only the Main View GestureRecognizer is fire.
Here is my custom GestureRecognizer (which intercepts every touch event):
import UIKit
import UIKit.UIGestureRecognizerSubclass
class MainGestureRecognizer: UIGestureRecognizer {
override func touchesBegan(touches: NSSet!, withEvent event: UIEvent!) {
super.touchesBegan(touches, withEvent: event);
//nextResponder() ??
state = UIGestureRecognizerState.Began;
}
override func touchesMoved(touches: NSSet!, withEvent event: UIEvent!) {
super.touchesMoved(touches, withEvent: event);
//nextResponder() ??
state = UIGestureRecognizerState.Changed;
}
override func touchesEnded(touches: NSSet!, withEvent event: UIEvent!) {
super.touchesEnded(touches, withEvent: event);
//nextResponder() ??
state = UIGestureRecognizerState.Ended;
}
override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) {
super.touchesCancelled(touches, withEvent: event);
//nextResponder() ??
state = UIGestureRecognizerState.Cancelled;
}
}
Maybe I should use nextResponder, but I have only found Obj-C code like:
[self.nextResponder touchesBegan:touches withEvent:event];
What's the trick to pass an event to the next responder in the responder chain?
Is there a way to pass touches through on the iPhone?
So the question is, what should I do to make the second event (the SubView Event) fire too?
Is there a function like nextResponder in Swift?

Ôh ! Here is the Swift code for nextResponder :
https://stackoverflow.com/a/26510277/4135158

Related

Forced Touch with tvOS

Does anybody know how to detect a forced touch/click on the remote control with tvOS?
I want to use the click in a Sprite Kit scene to open a 'game paused alert'. I have no UIKit controls which have the focus and will react on the click.
I'm already using the 'normal' touch events on the remote control to move my sprites around.
Apple suggests using UIPressesEvent's to detect presses/clicks.
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
for item in presses {
if item.type == .Select {
self.view.backgroundColor = UIColor.greenColor()
}
}
}
override func pressesEnded(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
for item in presses {
if item.type == .Select {
self.view.backgroundColor = UIColor.whiteColor()
}
}
}
override func pressesChanged(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
// ignored
}
override func pressesCancelled(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
for item in presses {
if item.type == .Select {
self.view.backgroundColor = UIColor.whiteColor()
}
}
}

tvOS UIPress gestures not being recognized in subclass of SKScene

I am trying to respond to a press in a subclass of SKScene. I can override the responder pressesEnded inside of my ViewController just fine, but when I move my pressesEnded override into my SKScene sub class I no longer receive any calls.
Below is my pressesEnabled override, which works as intended inside of ViewController
override func pressesEnded(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
print("press")
}
Anybody know how to receive button presses inside of a SKScene?
You need to forward your press events from your ViewController to the SKScene, like so...
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
gameScene.pressesBegan(presses, withEvent: event)
}
override func pressesEnded(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
gameScene.pressesEnded(presses, withEvent: event)
}
Then in gameScene (SKScene) do something like:
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
for press in presses {
switch press.type {
case .UpArrow:
print("Up Arrow")
case .DownArrow:
print("Down arrow")
case .LeftArrow:
print("Left arrow")
case .RightArrow:
print("Right arrow")
case .Select:
print("Select")
case .Menu:
print("Menu")
case .PlayPause:
print("Play/Pause")
}
}
}
override func pressesEnded(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
print("Presses Ended.")
}
The "Arrow" presses are sent when the user taps the edges of the touchpad, but aren't recognized in the simulator. "Select" is sent when the center of the touchpad is tapped.
I hope this helps!
Use pressesBegan to map a physical button (Menu, PlayPause), and pressesBegan or pressesEnded for the trackpad of the Apple TV Remote (left, right, etc).
If you press on a "button" of the trackpad and move to another location and release, the method pressesEnded is not called, you can't do this with a physical button.
Presses Began:
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
print("Press began")
for item in presses {
if item.type == .PlayPause {
print("PlayPause")
}
}
}
Presses Ended:
override func pressesEnded(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
print("Press Ended")
for item in presses {
if item.type == .RightArrow {
print("Right Arrow")
}
}
}

Iterating over NSObject set as a certain type

I have a function that that receives a Set<NSObject> and I need to iterate over the set as a Set<UITouch>. How exactly do I test for this and unwrap the set?
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch in touches {
// ...
}
}
Generally you would use a conditional cast to check each element
for its type. But here, the touches parameter is
documented
as
A set of UITouch instances that represent the touches that are moving
during the event represented by event.
therefore you can force-cast the entire set:
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch in touches as! Set<UITouch> {
// ...
}
}
Note that in Swift 2 the function declaration changed to
func touchesMoved(_ touches: Set<UITouch>, withEvent event: UIEvent?)
(due to the "light-weight generics" in Objective-C) so that a cast is not needed anymore.
Use the as operator to perform type casting:
for touch in touches {
if let aTouch = touch as? UITouch {
// do something with aTouch
} else {
// touch is not an UITouch
}
}

SKSpriteNode not detecting touch events

I can not get the touchesBegan function to fire. It isn't being called when a user touched the node.
import SpriteKit
class SimpleButton: SKSpriteNode {
//called when the user taps the button
override func touchesBegan(touches: NSSet!, withEvent event: UIEvent!) {
println("touches began")
}
//called when the user finishes touching the button
override func touchesEnded(touches: NSSet!, withEvent event: UIEvent!) {
println("touches ended")
}
override func touchesMoved(touches: NSSet!, withEvent event: UIEvent!) {
println("touches moved")
}
}
The answer is, You need to enable touches using the userInteractionEnabled parameter.
let imageTexture = SKTexture(imageNamed: "a_button")
let sprite: SimpleButton = SimpleButton(texture: imageTexture)
sprite.userInteractionEnabled = true // <--- This is required, it defaults to false.
sprite.position = CGPoint(x:CGRectGetMidX(self.frame) - 200, y:CGRectGetMidY(self.frame));
sprite.color = UIColor.blackColor()
sprite.colorBlendFactor = 1.0
self.addChild(sprite)

issue enabling dataDetectorTypes on a UITextView in a UITableViewCell

I have a UITextView inside a UITableViewCell in a table. "editable" for the UITextView is turned off, which allows me to set dataDetectorTypes to UIDataDetectorTypeAll, which is exactly what I want. The app now detects when the user touches a link in the UITextView, and does the appropriate thing.
The problem arises when the user touches on part of the UITextView where there is no link. I want the didSelectRowAtIndexPath in the UITableView delegate to be called. But it isn't, because the UITextView is trapping the touch, even when no link is detected.
My first guess was to turn userInteractionEnabled on the UITextView to NO. This means that didSelectRowAtIndexPath will get called, but then the UITextView can't detect links. It's a catch-22.
Any ideas on how to fix this?
Thanks for any help.
Maybe you could try passing the touch up the responder chain.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
}
Override all four of the UIResponder touch handlers to forward to the text view's superview.
The header file states that "Generally, all responders which do custom touch handling should override all four of these methods. … You must handle cancelled touches to ensure correct behavior in your application. Failure to do so is very likely to lead to incorrect behavior or crashes."
class MyTextView: UITextView {
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.superview?.touchesBegan(touches, withEvent: event)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.superview?.touchesMoved(touches, withEvent: event)
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.superview?.touchesEnded(touches, withEvent: event)
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
self.superview?.touchesCancelled(touches, withEvent: event)
}
}