How to Recognize Continuous Touch in Swift

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



Leave a reply



Submit