Check which image view was pressed using UITapGestureRecognizer in Swift - swift

I have three UITapGestureRecognizers.
They look like that:
gestureImageViewUp = UITapGestureRecognizer(target: self, action: #selector(ViewController.checkChoice(_:)))
self.imageViewUp.addGestureRecognizer(gestureImageViewUp)
gestureImageViewDown = UITapGestureRecognizer(target: self, action: #selector(ViewController.checkChoice(_:)))
self.imageViewDown.addGestureRecognizer(gestureImageViewDown)
gestureImageViewMiddle = UITapGestureRecognizer(target: self, action: #selector(ViewController.checkChoice(_:)))
self.imageViewMiddle.addGestureRecognizer(gestureImageViewMiddle)
I want to check which of them was pressed. How can I solve that?

You shouldn't need more then one recogniser, just attach it to the view and in the selector check which imageview was clicked.
func onPress(_ guesture: UIGestureRecognizer) {
guard let location = guesture.location(in: self.view) else { return }
if gestureImageViewUp.frame.contains(location) {
// …
}
if gestureImageViewDown.frame.contains(location) {
// …
}
if gestureImageViewMiddle.frame.contains(location) {
// …
}
}
Not tested sorry, it would be easier if you pasted code instead of snapshots

Related

Tap gesture (gesture began) not recognised in Swift

UITapGestureRecogniser began state is not recognised, only ended is recognised.
override func viewDidLoad() {
let tapgr = UITapGestureRecognizer(target: self, action: #selector(tapTrigger(recongizer:)))
bottomBar.addGestureRecognizer(tapgr)
}
#objc func tapTrigger(recongizer: UITapGestureRecognizer){
if recongizer.state == .began{
print("recognised") // does not print
}else if recogniser.state == .ended{
print("ended") //prints
}
}
What I am trying to do is highlight a view(not the view the recogniser is added) when a touch is recognised and unhighlight when it is cancelled.
Instead of using UITapGestureRecognizer you can use UILongPressGestureRecognizer to get the different state.
Like this:
let tapgr = UILongPressGestureRecognizer(target: self, action: #selector(tapTrigger(recongizer:)))
tapgr.minimumPressDuration = 0
bottomBar.addGestureRecognizer(tapgr)
#objc func tapTrigger(recongizer: UITapGestureRecognizer){
if recongizer.state == .began{
print("recognised")
} else if recongizer.state == .ended{
print("ended") //prints
}
}

Prevent UIButton Long Press Repeating Function

The following UILongPressGestureRecognizer code works, however it repeatedly runs the long() press function when the button is held. I'd like to have it only run one time while the user is pressing. Is this possible?
override func viewDidLoad() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector (tap))
let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(long))
tapGesture.numberOfTapsRequired = 1
shiftBtn.addGestureRecognizer(tapGesture)
shiftBtn.addGestureRecognizer(longGesture)
}
#objc func tap() {
print("Short Tap")
}
#objc func long() {
print("Long press")
}
Thanks!
You should call the long When gesture activated. it's called one time whenever long gesture active.
#objc func hitlongprass(_ sender : Any){
guard let longPress = sender as? UILongPressGestureRecognizer else
{ return }
if longPress.state == .began { // When gesture activated
long()
}
else if longPress.state == .changed { // gesture Calls multiple times by time changed
}
else if longPress.state == .ended { // When gesture end
}
}
func long() {
print("Long press")
}
Calling:
let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(hitlongprass(_:)))
You can check state of gesture in long function. Ex check state is begin long press

selector with argument gestureRecognizer

Argument of '#selector' does not refer to an '#objc' method, property,
or initializer
Problem : Above Error when i try to pass argument with selector
code snippet:
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(labelPressed(i: 1)))
func labelPressed(i: Int){
print(i)
}
You cannot pass a parameter to a function like that. Actions - which this is, only pass the sender, which in this case is the gesture recognizer. What you want to do is get the UIView you attached the gesture to:
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(labelPressed())
func labelPressed(_ recognizer:UITapGestureRecognizer){
let viewTapped = recognizer.view
}
A few more notes:
(1) You may only attach a single view to a recognizer.
(2) You might want to use both the `tag` property along with the `hitTest()` method to know which subview was hit. For example:
let view1 = UIView()
let view2 = UIView()
// add code to place things, probably using auto layout
view1.tag = 1
view2.tag = 2
mainView.addSubview(view1)
mainView.addSubview(view2)
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(mainViewTapped())
func mainViewTapped(_ recognizer:UITapGestureRecognizer){
// get the CGPoint of the tap
let p = recognizer.location(in: self)
let viewTapped:UIView!
// there are many (better) ways to do this, but this works
for view in self.subviews as [UIView] {
if view.layer.hitTest(p) != nil {
viewTapped = view
}
}
// if viewTapped != nil, you have your subview
}
You just should declare function like this:
#objc func labelPressed(i: Int){ print(i) }
Update for Swift 3:
Using more modern syntax, you could declare your function like this:
#objc func labelTicked(withSender sender: AnyObject) {
and initialize your gesture recognizer like this, using #selector:
UITapGestureRecognizer(target: self, action: #selector(labelTicked(withSender:)))

TVOS : detecting touches with press began and functions (Swift Spritekit)

im trying to define touches in TVOS with press began but its not working.
i want to connect 3 functions
Start Game
Play Pause Music
Restart Game
Game scene TVOS:
func StartGameRecognizer(gesture: UITapGestureRecognizer) {
if isGameOver {
} else if !isStarted {
start()
} else {
hero.flip()
}
}
func playPauseMusicRecognizer(gesture: UITapGestureRecognizer) {
let onoroff = UserDefaults.standard.bool(forKey: "onoroff")
if !onoroff { //playing is false
Singleton.sharedInstance().pauseBackgroundMusic()
SoundOnOff.texture = SKTexture(imageNamed:"Sound-off.png")
UserDefaults.standard.set(true, forKey: "onoroff")
}
else {
Singleton.sharedInstance().resumeBackgroundMusic()
SoundOnOff.texture = SKTexture(imageNamed:"Sound-on.png")
UserDefaults.standard.set(false, forKey: "onoroff")
}
}
func RestartGameRecognizer(gesture: UISwipeGestureRecognizer){
print("RestartGame")
//Re-open GameScene
GameViewController().TitleGameOver.isHidden = true
GameViewController().RestartButton.isHidden = true
GameViewController().scoreTextLabel.isHidden = true
GameViewController().highscoreTextLabel.isHidden = true
GameViewController().ScoreBoardTV.isHidden = true
GameViewController().Score.isHidden = true
GameViewController().HighScore.isHidden = true
GameViewController().NewhighscoreTextLabel.isHidden = true
GameViewController().HomeButton.isHidden = true
// Singleton.sharedInstance().resumeSoundEffectClickedButton()
GameViewController().gameDidStart()
}
GameViewControllerTVOS:
override func pressesBegan(_ presses: Set<UIPress>, with 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")
default:
print("")
}
}
}
How i can use it right?
How can i transfer functions between scene to view controller?
I need example or hint to write the code right.
Update:
GameSceneTvOS:
override func didMove(to view: SKView) {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(GameSceneTVOS.StartGameRecognizer(gesture:)))
tapGesture.allowedPressTypes = [NSNumber(value: UIPressType.Select.rawValue)]
view.addGestureRecognizer(tapGesture)
let tapGesture1 = UITapGestureRecognizer(target: self, action: #selector(GameSceneTVOS.PlaypauseMusicRecognizer(gesture:)))
tapGesture1.allowedPressTypes = [NSNumber(value: UIPressType.PlayPause.rawValue)]
view.addGestureRecognizer(tapGesture1)
let swipeUp = UISwipeGestureRecognizer(target: self, action: #selector(GameSceneTVOS.RestartGameRecognizer(gesture:)))
swipeUp.direction = UISwipeGestureRecognizerDirection.up
self.view?.addGestureRecognizer(swipeUp)
}
**Functions :**
func StartGameRecognizer(gesture: UITapGestureRecognizer) {
print("StartGame")
if isGameOver {
} else if !isStarted {
start()
} else {
hero.flip()
}
}
func PlaypauseMusicRecognizer(gesture: UITapGestureRecognizer) {
print("PlaypauseMusic")
let onoroff = UserDefaults.standard.bool(forKey: "onoroff")
if !onoroff { //playing is false
Singleton.sharedInstance().pauseBackgroundMusic()
SoundOnOff.texture = SKTexture(imageNamed:"Sound-off.png")
UserDefaults.standard.set(true, forKey: "onoroff")
}
else {
Singleton.sharedInstance().resumeBackgroundMusic()
SoundOnOff.texture = SKTexture(imageNamed:"Sound-on.png")
UserDefaults.standard.set(false, forKey: "onoroff")
}
}
func RestartGameRecognizer(gesture: UISwipeGestureRecognizer){
print("RestartGame")
//Re-open GameScene
GameViewController().TitleGameOver.isHidden = true
GameViewController().RestartButton.isHidden = true
GameViewController().scoreTextLabel.isHidden = true
GameViewController().highscoreTextLabel.isHidden = true
GameViewController().ScoreBoardTV.isHidden = true
GameViewController().Score.isHidden = true
GameViewController().HighScore.isHidden = true
GameViewController().NewhighscoreTextLabel.isHidden = true
GameViewController().HomeButton.isHidden = true
// Singleton.sharedInstance().resumeSoundEffectClickedButton()
GameViewController().gameDidStart()
}
You code has some problems.
1) This code is wrong in the restartGame method.
GameViewController().TitleGameOver.isHidden = true
GameViewController().RestartButton.isHidden = true
...
You are creating a new instance of GameViewController on every line, you are not referencing the current game view controller.
2) You should not be using your GameViewController to create your UI, you should be doing it directly in the relevant SKScenes using only SpriteKit APIs (SKLabelNodes, SKSpriteNodes, SKNodes etc). Using UIKit in SpriteKit, except in some occasions, is bad practice.
3) You should be using TouchesBegan, TouchesMoved etc directly in the SKScenes to get touch input, dont use the GameViewController method.
They fill fire just like they do when you are on iOS.
You can also create gesture recognizers in your SKScene to get button presses from the SiriRemote.
/// Pressed, not tapped, main touch pad
let pressedMain = UITapGestureRecognizer(target: self, action: #selector(SOMEMETHOD))
pressedMain.allowedPressTypes = [NSNumber(value: UIPressType.select.rawValue)]
view?.addGestureRecognizer(pressedMain)
/// Pressed play pause button
let pressedPlayPause = UITapGestureRecognizer(target: self, action: #selector(SOMEMETHOD))
pressedPlayPause.allowedPressTypes = [NSNumber(value: UIPressType.playPause.rawValue)]
view?.addGestureRecognizer(pressedPlayPause)
/// Pressed menu button
let pressedMenu = UITapGestureRecognizer(target: self, action: #selector(SOMEMETHOD))
pressedMenu.allowedPressTypes = [NSNumber(value: UIPressType.menu.rawValue)]
view?.addGestureRecognizer(pressedMenu)
You can also use swipe gesture recognizers if you want
let rightSwipe = UISwipeGestureRecognizer(target: self, action: #selector(SOMEMETHOD))
rightSwipe.direction = .right
view?.addGestureRecognizer(rightSwipe)
let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(SOMEMETHOD))
leftSwipe.direction = .left
view?.addGestureRecognizer(leftSwipe)
let upSwipe = UISwipeGestureRecognizer(target: self, action: #selector(SOMEMETHOD))
upSwipe.direction = .up
view?.addGestureRecognizer(upSwipe)
let downSwipe = UISwipeGestureRecognizer(target: self, action: #selector(SOMEMETHOD))
downSwipe.direction = .down
view?.addGestureRecognizer(downSwipe)
If you are using gesture recognisers, remember they are added to the GameViewController (view?.addGesture...) so its good practice to remove them when you add either new ones, or if you change to a new scene where you might need different ones.
Call this code when you exit a scene or add new gesture recognizers.
for gestureRecognizer in view?.gestureRecognizers ?? [] {
view?.removeGestureRecognizer(gestureRecognizer)
}
If you are looking for fully fledged micro gamepad support than you will need to watch some tutorials about the gameController framework.
4) Try putting your string keys like the ones for UserDefaults in some property.
enum Key: String {
case onoroff
}
and than use it like so
UserDefaults.standard.set(true, forKey: Key.onoroff.rawValue)
to avoid making typos.
5) You should be following the Swift conventions consistently, some of your methods and properties start with capital letters but they shouldn't.
I would advise that you restructure your code and not continue with this approach of trying to use the GameViewController for all this. It should be all done directly in the relevant SKScene.
EDIT. I think you are calling the selector wrong, try this. When your function has a parameter you would use this (_:), you are trying to use (gesture:). Try this instead.
... action: #selector(startGameRecognizer(_:))
Hope this helps

AVPlayercontroller - Adding Overlay Subviews

Depends upon the PlaybackControl Visibity How to show and hide the Custom Subview added in contentOverlayView?
I want to do like Youtube TVOS app did.
I tried with UIPressesEvent but it is not giving me the exact touch events. It is giving me these:
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
for item in presses {
switch item.type {
case .Menu:
self.customViews.alpha = 0
case .PlayPause:
self.player?.pause()
self.customViews.alpha = 0
default:
self.setVisibilityToPreviewView()
}
}
}
func setVisibilityToPreviewView () { //This wont work in all cases.
if self.previewView.alpha == 1 {
self.previewView.alpha = 0
} else {
self.previewView.alpha = 1
}
}
But with this Touch events i can only show and hide the subviews.
It should be hidden when the playbackcontrol is Hidden.
If I get the PlayBackControl Visibility values I don't need to worry about hiding these subviews.
Apple is Using AVNowPlayingPlaybackControlsViewController. It is not open for developers.
So I need to find some other better way to do this.
Please guide me how to do it.
You can register a tapGesture recognizer and then set its allowPressTypes property to UIPressType.Select, something like this
let tapRecognizer = UITapGestureRecognizer(target: self, action: "onSelect:")
tapRecognizer.allowedPressTypes = [NSNumber(integer: UIPressType.Select.rawValue)];
self.view.addGestureRecognizer(tapRecognizer)
And inside your action button show or hide custom overlays.
Example: Add this code inside a view controller and on tap (selecting at empty area on front of remote, touch area) you will see a message on console.
override func viewDidLoad() {
super.viewDidLoad()
let tapGesture = UITapGestureRecognizer(target: self, action: "onSelect")
tapGesture.allowedPressTypes = [NSNumber(integer: UIPressType.Select.rawValue)]
self.view.addGestureRecognizer(tapGesture);
}
func onSelect(){
print("this is select gesture handler method");
}
Update: Below is the code which will create AVPlayerController and will register tapGestureRecognizer to playervc.view.
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
playContent()
}
func playContent(){
let urlString = "<contentURL>"
guard let url = NSURL(string: urlString) else{
return
}
let avPlayer = AVPlayer(URL: url)
let playerVC = AVPlayerViewController()
playerVC.player = avPlayer
self.playerObj = playerVC
let tapGesture = UITapGestureRecognizer(target: self, action: "onSelect")
tapGesture.allowedPressTypes = [NSNumber(integer: UIPressType.Select.rawValue)]
self.view.addGestureRecognizer(tapGesture);
playerVC.view.addGestureRecognizer(tapGesture)
self.presentViewController(playerVC, animated: true, completion: nil);
}
Give a try to this, I think it should work fine.