touchesBegan not firing in PDFView - ios

I am trying to determine the location of a touch on a PDFView. I have set my pdf view to be user interacted as follows:
pdfView?.isUserInteractionEnabled = true
I then use the following function to detect touches:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let position = touch.location(in: pdfView)
print(position)
}
}
The touchesBegan code is never fired.

Add gesture recognizer to PDFView like below:
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTap(_:)))
tapGesture.numberOfTapsRequired = 1
if var recognizer = pdfView.gestureRecognizers {
recognizer.append(tapGesture)
pdfView.gestureRecognizers = recognizer
}

Related

touchesBegan and touchesMoved also called during pinch

I have added a pinch gesture and a pan gesture in a view. I am also using touchesBegan and touchesMoved method. Surprisingly when i am pinching my view it is sometimes also calling touchesBegan and touchesMoved.How to stop calling this methods during pinching? Here is what i did.
class CustomView: UIView {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
if let touchCount = event?.touches(for: self)?.count {
if touchCount == 1 {
// Doing some task
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
if let touchCount = event?.touches(for: self)?.count {
if touchCount == 1 {
// Doing some task
}
}
}
}
In my ViewController: I created a customView object of CustomView class and added some gestures like below:
let pinch = UIPinchGestureRecognizer(target: self, action: #selector(pinch(recognizer:)))
customView.addGestureRecognizer(pinch)
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(recognizer:)))
panGesture.minimumNumberOfTouches = 2
self.customView.addGestureRecognizer(panGesture)
touchesBegan and touchesMoved are really, really generic -- whenever your finger touches down or moves, they'll be called. This includes button presses and just pretty much every thing that your finger can touch.
So if you're using gesture recognizers for pan and pinch, stick with gesture recognizers. Use an UITapGestureRecognizer instead of relying on touchesBegan, and another UIPanGestureRecognizer for touchesMoved.

Tap gesture to NOT occur when touching a specific location - SpriteKit

I have used touchesBegan to provide functionality for my UIButtons and have used a tapped gesture to provide functionality for my main player SKSpriteNode making it jump when triggered.
//Code regarding the UIButton touch
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//touches began is only used for GUI buttons -> not to affect player
for touch: AnyObject in touches {
//We get location of the touch
let locationOfTouch = touch.location(in: self)
if muteButton.contains(locationOfTouch) { //mute the game
timer.invalidate()
audioPlayer.volume = 0
}
//Code regarding the tap
let tap = UITapGestureRecognizer(target: self, action: #selector(GameScene.tapped(gesture:)))
tap.cancelsTouchesInView = false
self.view!.addGestureRecognizer(tap)
......
func tapped(gesture: UIGestureRecognizer) { //used to make the player jump
player.physicsBody!.applyImpulse(CGVector(dx: 0, dy: 60))
player.physicsBody!.affectedByGravity = true */
}
My problem is that when I press on the restartButton the tap gesture is also activated later when the touch ends. Is there anything I can do?
The main issue is that the two separate systems for detecting touches (using gesture recognizers and using the touchesBegan/Moved/Ended methods) are in conflict.
One solution is to enable and disable the gesture recognizer if the touch is inside one of the buttons.
In the touchesBegan method, if the touch is inside a button, disable the tap gesture recognizer:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let locationOfTouch = touch.location(in: self)
if muteButton.contains(locationOfTouch) {
// mute action
tap.isEnabled = false
}
}
}
Then in touchesEnded and touchesCancelled, re-enable the gesture recognizer:
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
tap.isEnabled = true
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
tap.isEnabled = true
}
This way, if the touch is inside a button, the tap gesture recognizer will not fire. Whenever any touch is complete, we always re-enable the gesture recognizer in case the next touch is meant to make the player jump.
I have tested this out in an empty project, and it works.
Hopefully that helps! Good luck with your game.

Function to detect if there's any touch occurring on the screen

I'm trying to create a simple function, similar to the touchesBegan, that detects if there's any touch occurring on the screen.
I've hit a brick wall trying it out myself because I'm not comfortable with UITouch class, but I really need some self made function, outside the touchesBegan default one.
I was trying to do something like this 'pseudo-code/swift'
func isTouchingTheScreen() -> Bool {
let someTouchHandleConstant: uitouch ???
if imTouchingTheScreen {
return true
} else {
return false
}
}
Do you have any hints?
PS: I know that code doesn't work, don't call that out, it was just to give you some 'image' of what I was trying to do (:
The idea
You can simply keep track of every touch begun, ended or cancelled by the user.
class GameScene: SKScene {
private var activeTouches = Set<UITouch>()
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
activeTouches.unionInPlace(touches)
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
activeTouches.subtractInPlace(touches)
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
if let touches = touches {
activeTouches.subtractInPlace(touches)
}
}
var isTouchingTheScreen: Bool { return !activeTouches.isEmpty }
}
Keeping activeTouches updated
As you can see I am keeping updated the activeTouches Set.
Every time a touch does begin I add it to activeTouches. And every time a touch does end or is cancelled I remove it from activeTouches.
The isTouchingTheScreen computed variable
This allows me to define the isTouchingTheScreen computed property that simply returns true when the Set contains some element.
You can implement UITapGestureRecognizer as below:
var tapGesture :UITapGestureRecognizer!
override func didMoveToNode() {
// Add UITapGestureRecognizer to view
self.tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.touchedView(_:)))
view.addGestureRecognizer(tapGesture)
}
func touchedView(sender: UITapGestureRecognizer) {
print("view touched")
}
You could implement UITapGestureRecognizer:
// global var
var tapGesture :UITapGestureRecognizer!
override func didMoveToView() {
// Add tap gesture recognizer to view
self.tapGesture = UITapGestureRecognizer(target: self, action: #selector(GameScene.handleTap(_:)))
self.tapGesture.cancelsTouchesInView = false
view.addGestureRecognizer(tapGesture)
}
func handleTap(sender: UITapGestureRecognizer) {
print("GameScene tap")
if sender.state == .Ended {
var positionInScene: CGPoint = sender.locationInView(sender.view)
positionInScene = self.scene!.convertPointFromView(positionInScene)
let touchedNode = self.nodeAtPoint(positionInScene)
if touchedNode.name != "myHero" {
print("The SKSpriteNode myHero was tapped")
}
}
}
You can find more details in Apple docs here.

Disable touches everywhere except inside of a button? - Swift

When I die in my game, I want to ignore all touch events by the user EXCEPT if the user taps inside of or on the reset game button. Here is my code.
for touch in touches{
let location = touch.locationInNode(self)
if died == true{
Ball.physicsBody?.velocity = CGVectorMake(0, 0)
if resetGame.containsPoint(location){
restartScene()
runAction(SKAction.playSoundFileNamed("Woosh.wav", waitForCompletion: false))
}
else {
self.userInteractionEnabled = false
}
This is all inside of my touchesBegan. This was my attempt at ignoring the user's touch unless the location of the touch was within the size of button. How can I ignore a user's touches everywhere on the screen except the button? resetGame is an SKSpriteNode image.
There are two solutions to your issue.
The first case I want to propose to you is based to gesture recognizer.
You can separate the button from the other touches events and switch on/off the touches event by a boolean var like this:
Gesture recognizers:
In the global var declaration section of your class:
var tapGesture :UITapGestureRecognizer!
var enableTouches:Bool = true
override func didMoveToView(view: SKView) {
super.didMoveToView(view)
self.tapGesture = UITapGestureRecognizer(target: self, action: #selector(GameClass.simpleTap(_:)))
self.tapGesture.cancelsTouchesInView = false
view.addGestureRecognizer(tapGesture)
myBtn.name = "myBtn"
}
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
return self.enableTouches
}
func simpleTap(sender: UITapGestureRecognizer) {
print("simple tap")
if sender.state == .Ended {
var touchLocation: CGPoint = sender.locationInView(sender.view)
touchLocation = self.convertPointFromView(touchLocation)
let touchedNode = self.nodeAtPoint(touchLocation)
// do your stuff
if touchedNode.name == "myBtn" {
// button pressed, do your stuff
}
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
if died == true {
self.enableTouches = false // disable all touches but leave gestures enabled
//do whatever you want when hero is died
}
}
Only a Boolean
The second solution I want to propose is simply to stopping touches flow by using a simple boolean (it's not very elegant but it works).
This method look when button is tapped and the update method check if your hero is dead so all touches will be disabled:
In the global var declaration section of your class:
var enableTouches:Bool = true
override func didMoveToView(view: SKView) {
super.didMoveToView(view)
myBtn.name = "myBtn"
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if (!enableTouches) {
return
}
let touch = touches.first
let positionInScene = touch!.locationInNode(self)
let touchedNode = self.nodeAtPoint(positionInScene)
// do your stuff
if touchedNode.name == "myBtn" {
// button pressed, do your stuff
if died == true {
self.enableTouches = false // disable all touches
//do whatever you want when hero is died
}
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
if (!enableTouches) {
return
}
let touch = touches.first
let positionInScene = touch!.locationInNode(self)
let touchedNode = self.nodeAtPoint(positionInScene)
// do your stuff
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
if (!enableTouches) {
return
}
}
The first case permit to you to have always the gesture enabled so you can do also other stuff with gestures when your hero will be died. The second case stop your touches when you press your button and do the "die flow". Choose which may be the most suitable for you.

how i can differentiate between a gesture and a touch in spriteKit and swift?

i have two functions, one is activated when i touch the scene and another one when i make a gesture down, but when i make a gesture the scene detect a touch and execute both functions
class GameScene: SKScene, SKPhysicsContactDelegate {
override func didMoveToView(view: SKView) {
/* Setup your scene here */
// physics & collisions
physicsWorld.gravity = CGVectorMake(0.0, 0.0)
physicsWorld.contactDelegate = self
// Swipe down
let swipeDown:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: Selector("swipedDown:"))
swipeDown.direction = .Down
view.addGestureRecognizer(swipeDown)
}
//MARK: Swipes
func swipedDown(sender:UISwipeGestureRecognizer){
//first function
swipeDown()
}
//MARK: Touches
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch in touches {
let location = touch.locationInNode(self)
// second function
attack()
}
}
}
Instead of touchesBegan, try using a tap gesture (UITapGestureRecognizer) for attack action.
This should not be necessary but if you still get conflict between swipe and tap, make the tap gesture depend on swipe's failure using requireGestureRecognizerToFail to ensure that a tap is not detected during a swipe.
You could try something like this
var swiped = Bool()
func swipedDown(sender:UISwipeGestureRecognizer){
//first function
swipeDown()
swiped = true
}
Override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch in touches {
let location = touch.locationInNode(self)
// second function
if swiped == false {
attack()
}
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
swiped = false
}
}
Hope this helps.

Resources