How to recognize continuous touch in Swift?
The most difficult thing about this process is tracking single touches within a multitouch environment. The issue with the "simple" solution to this (i.e., turn "istouched" on in touchesBegan
and turn it off in touchesEnded
) is that if the user touches another finger on the screen and then lifts it, it will cancel the first touch's actions.
To make this bulletproof, you need to track individual touches over their lifetime. When the first touch occurs, you save the location of that touch and move the object towards that location. Any further touches should be compared to the first touch, and should be ignored if they aren't the first touch. This approach also allows you to handle multitouch, where the object could be made to move towards any finger currently on the screen, and then move to the next finger if the first one is lifted, and so on.
It's important to note that UITouch
objects are constant across touchesBegan
, touchesMoved
, and touchesEnded
. You can think of a UITouch
object as being created in touchesBegan
, altered in touchesMoved
, and destroyed in touchesEnded
. You can track the phase of a touch over the course of its life by saving a reference to the touch object to a dictionary or an array as it is created in touchesBegan
, then in touchesMoved
you can check the new location of any existing touches and alter the object's course if the user moves their finger (you can apply tolerances to prevent jitter, e.g., if the x/y distance is less than some tolerance, don't alter the course). In touchesEnded
you can check if the touch in focus is the one that ended, and cancel the object's movement, or set it to move towards any other touch that is still occurring. This is important, as if you just check for any old touch object ending, this will cancel other touches as well, which can produce unexpected results.
This article is in Obj-C, but the code is easily ported to Swift and shows you what you need to do, just check out the stuff under "Handling a Complex Multitouch Sequence": https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/multitouch_background/multitouch_background.html
Continuous Touch in Swift
My intuition screams that your while loop blocks the main thread.
The while does not delay between iterations, instead the calling of the callback gets delayed. There are no delays between loops so the main thread gets blocked and the touchup function has no occasion to run.
You could change this to
func touchDown(atPoint pos : CGPoint) {
print("Touched Down in \(purpose) down arrow")
arrowIsPressed = true
self.texture = SKTexture(imageNamed: "bottomArrowPressed.png")
adjustBlue() // Because you want one immediate action, in case there is no continuous touch
callback()
}
func touchUp(atPoint pos : CGPoint) {
arrowIsPressed = false
self.texture = SKTexture(imageNamed: "bottomArrow.png")
adjustCounter = 0
}
// MARK: - Touch Helpers
@objc func callback() {
adjustBlue()
// loop in a non blocking way after 0.5 seconds
DispatchQueue.main.asynAfter(deadline: .now() + 0.5) {
if self.arrowIsPressed {
self.callback()
}
}
}
func adjustBlue() {
adjustCounter += 1
print("Adjust Action \(adjustCounter)")
// eventually useful code will go here
}
Detect continuous touch position in view with UIScrollView still active
I solved this by adding a panning gesture recognizer to my view and using it's translationInView
method (UISwipeGestureRecognizer
doesn't have this method). Example below
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(myMethod(_:)))
panGesture.delegate = self
self.addGestureRecognizer(panGesture)
func myMethod(sender: UIPanGestureRecognizer) {
// sender.translationInView(self).x
}
Also making sure to return true for shouldRecognizeSimultaneouslyWithGestureRecognizer
in the UIGestureRegognizerDelegate
to account for the scrollView.
Swift Detect Touch Anywhere
Dismissing a modal view turns out to be surprisingly easy. All you need to do is call dismissViewControllerAnimated(true, completion: nil)
. Thus, to do what I wanted, all I needed to do was this:
override func touchesEnded(touches: NSSet, withEvent event: UIEvent)
{
dismissViewControllerAnimated(true, completion: nil)
super.touchesEnded(touches, withEvent: event)
}
How to detect touch event across multiple views on my view controller?
Do it like this
class YourCustomView : UIView {
func addTapGesture(action : @escaping ()->Void ){
self.gestureRecognizers?.forEach({ (gr) in
self.removeGestureRecognizer(gr)
})
let tap = MyTapGestureRecognizer(target: self , action: #selector(self.handleTap(_:)))
tap.action = action
tap.numberOfTapsRequired = 1
self.addGestureRecognizer(tap)
self.isUserInteractionEnabled = true
}
}
or you can use this even in a extension of UIView if you're going to use it in multiple types of UIViews.
And then use it like:
let yourView = YourCustomView()
yourView.addTapGesture{[weak self] in
//implement tap event here
}
Notice that [weak self] is going to avoid getting a strong reference for closure to avoid a retain cycle there.
iOS event for continuous touch
Based on your updated question it appears you need to setup a repeating timer in touchesBegan
. Each time the timer fires, update the offset. Cancel the timer in the touchesEnded
and touchesCanceled
methods.
I want to know the number of fingers such as two-finger simultaneous touch
If you want to know the number of fingers
Just do touches.count
, but make sure to set view.isMultipleTouchEnabled
to true. However, consider using pan gestures instead. They're easy to use and will save you a lot of code.
Edit: If you're using UIGestureRecognizer
, you shouldn't be using touchesBegan
and touchesMoved
. Instead, connect your gesture recognizer to an @IBAction
.
@IBAction func handlePan(_ sender: UIPanGestureRecognizer) {
print("Number of touches: \(sender.numberOfTouches)")
}
Related Topics
Swift: How to Fully Strip Internal/Inline Symbols
Accessing Self from Instance Properties Which Are Closures
Forcing Nspersistentcontainer Change Core Data
Swift: Dictionary Access via Index
Difference Between Dispatchqueue Types in Swift
In Swift, When Using "[Weak Self] In", Should I Double Up on It When Nested Inside Another Closure
How to Retrieve the Type of an Object in Swift
Centering the Camera on a Node in Swift Spritekit
Xcode 8 Swift Update with Error "Use Legacy Swift Language Version"
Create Instance of Class Known at Runtime in Swift
Get the Current Position of Scrollview in Swiftui
How to Convert Nsurl to String in Swift
Speed Up Xcode Swift Build Times
Uiimage Created from Mtkview Results in Color/Opacity Differences
Module File's Deployment Target Is iOS9.0 V9.0 with Xcode 7/Swift 2
In Swiftui How to Set the Environment Variable of Editmode in an Xcodepreview