Trigger UIPanGestureRecognizer immediately when it's added - swift

Can a UIPanGestureRecognizer be added while the user is touching and immediately start recognizing the pan gesture? I can only get it to work if I lift up my finger, touch again and start dragging.
From another answer, I've tried to subclass UIPanGestureRecognizer and override the touch event:
import UIKit.UIGestureRecognizerSubclass
class InstantPanGestureRecognizer: UIPanGestureRecognizer {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
if (self.state == UIGestureRecognizer.State.began) { return }
super.touchesBegan(touches, with: event)
self.state = UIGestureRecognizer.State.began
}
}
This doesn't solve my problem though, probably because they already had their UIPanGestureRecognizer added, and I want to add mine while the user is already touching the screen and have it work at that point.
I'm switching between adding swipe and pan gestures depending on where the user the is interacting on an image. The require(tofail:UIGestureRecognizer) function hasn't worked for me.

Related

UIView pass through touches only if more than one finger?

My UIView already handles single-finger touches with gesture recognisers for tap and pan just fine.
However, I would like touches with two fingers to be passed through to the parent view, behind this view. (The parent is a WKWebView with a javascript generated map that I'd like the user to be able to pinch-zoom, even while this other view is in front. This works OK when the other view is not in front, but of course when the front view is there, it doesn't pass through the touches.)
I have tried to detect this using either of the following in the front view, but in both cases, allTouches is an empty set (zero touches):
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
if let event = event {
print("\(event)")
if let touches = event.allTouches {
print("\(event.allTouches)")
if touches.count > 1 {
return false
}
}
}
return super.point(inside: point, with: event)
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if let event = event {
print("\(event)")
if let touches = event.allTouches {
print("\(event.allTouches)")
if touches.count > 1 {
return nil
}
}
}
return super.hitTest(point, with: event)
}
How can I continue to use my existing gesture recognisers, but pass through multi-finger touches to the superview?
More of a work-around than an actual answer, but here's what solved it for me...
Instead of the in-front child view covering all of the parent view with a transparent layer, I reduced it to only include the small area needed to actually present information and form fields to the user.
Then I changed the single-touch gestures to be added to the parent view, instead of to the child view.
So now NONE of the touches are captured by the child view (except for its form fields and buttons).
This is perhaps the better way to handle my particular situation anyhow. So I was probably asking the wrong question (X/Y issue!).

touchesBegan in static tableView not being called

I have read several posts here about same problem, but could not understood them mostly because I am quite new in IOS development and I use swift. Also I couldn't even found a definition for term "subclassing", maybe it is obj-c only?
Anyway, I have a tableview controller with static cells, and a textfield in one cell. I need to dismiss the keyboard when the user taps on a different area while editing the textfield. After reading posts here, I changed my touchesBegan content as following :
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
self.nextResponder()?.touchesBegan(touches, withEvent: event)
super.touchesBegan(touches, withEvent: event)
}
I still don't get the touches in tableviewcontroller which is defined as :
class addNew: UITableViewController, UITextFieldDelegate {
I had a similar issue on Swift 4 just to endEditing and hiding the keyboard with touchesBegan. I couldn't find a way around at first.
These two steps worked for me :
To add gesture recogniser to table view in :
override func viewDidLoad() {
super.viewDidLoad()
tableView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(hideKeyboard)))
}
Ending editing in two ways in
#objc func hideKeyboard() {
view.endEditing(true)
//textField.resignFirstResponder() /* This line also worked fine for me */
}
You can add a tapGestureRecognizer on top of you tableview.
Connect the tapGestureRecgonizer to a function/method.
Within that method, check if the textfield, is the firstresponder. If yes, then ask the textfield to resign first responder.

how to treat touches separately

I'm making a little game and I have come across a problem that I haven't been able to solve. The thing is that when I touch the screen an action occours. Well, I want that if there are 2 differents touches the action to happen 2 times, not only on the first one. Right now, if there are 2 players on the same device, the one who touches first is the one who wins, because the second player isn't able to even call the action. How can I invoke the action two times treating every touch recived as input?
In other words, I want to detect when there are two fingers on the screen and split every "finger" in the normal action for one finger.
Of course, my actions takes place here:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
//code to get input info
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
//calling actions with the arguments of touchesEnded and with the ones of touchesBegan
}
In your storyboard, you need to enable "Multiple Touch" for your view (it's in the Interaction section of the Attributes Inspector.) You can also set this property programmatically:
view.multipleTouchEnabled = true
However, if multiple touches happen at the same time, they will be passed in a single touchesBegan event. To make sure your app detects both touches, iterate over all of the touches in the set in touchesBegan:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
//code to get input info
}
}

Fastest way to detect touchesmoved moves over an UIView?

I'm making a customkeyboard, it has almost 30 buttons.
And i'm using multi-touch event to check which button is being selected or touch over.
My way is detect current finger position and compare with button position.
But it seems too slow because i have to use for loop to check every single button coordinates.
Any faster way to check touchesmoved touches over 1 UIView or UIButton?
For your keyboard buttons, you need to override the UIView method touchesBegan and touchesEnded. Touches began will be called when a touch enters the buttons frame, and touches ended will be called when a touch exits the buttons frame. No comparing of coordinates needed.
class MyButton: UIButton {
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
//Button presses
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
//Button unpresses
}
}
Note that there is a method known as touchesMoved which can be overriden in any UIView. This function is called any time touches move. You don't necessarily need to check any time a touch moves within the button, only when a touch begins and exits a button, so you shouldn't use the touchesMoved method in this case.

Long tap recognizer in Sprite Kit with swift

Hello I'm planning a game and an essential part of the game is to move left and right by pressing the right side of the screen or the left side.
But how can I detect a long press?
Many Thanks! :)
It is not called long tap. A tap can't be long. It is called UILongPressGestureRecognizer. You can take a look at the documents here
if you want to do something while the user is holding down on the screen, you could use the touchesBegan and touchesEnded methods to detect the hold.
var touching = false
func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
touching = true
}
func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
touching = false
}