How to allow only one UIImageView to be touched at a time - ios

I have built a simple memory game which consists of 16 UIImageViews.
For the memory game, you are only supposed to be able to touch one card at a time. When you touch the card, it flips over and reveals the image underneath
My issue is that I only want the user to be able to touch one image view at a time. When a user taps on two cards at the same time, it glitches the game. So my question is how do I allow only 1 UIImageView to perform an action at a time, and not allow multiple UIImageViews to perform an action at the same time if touched simultaneously.

Assuming that the user has to unflip a card by selecting it again, I would suggest adding a property to your viewController to keep track of the selectedCard. If there is already a selected card, ignore all others.
var selectedCard: UIImageView?
#objc func handleTap(_ recognizer: UITapGestureRecognizer) {
guard let imageView = recognizer.view as? UIImageView else { return }
if let selected = selectedCard {
if selected === imageView {
// unflip the card
imageView.image = backOfCard
selectedCard = nil
}
} else {
// display face of card
imageView.image = ...
selectedCard = imageView
}
}
Note: Even if a user taps two cards at the same time, handleTap will be called twice in succession. The first card will win and be flipped and become the selectedCard and the second card will be ignored because the if selected === imageView test will fail.

You have a number of choices.
You could put a single tap gesture recognizer on the superview that holds all of your card views and add logic to figure out which one was tapped. Since there is a single method to identify taps, you would't ever get more than one.
Alternately, you could add an instance variable to your class that keeps track of the state, and use it to set userInteractionEnabled to false on the image views that you don't want the user to tap.

Related

Detecting which ImageView has has been tapped

So i have 4 vStacks, each containing 9 ImageViews. Each ImageView represents one Card, alpha 0 is default. When a Card is Detected (with ARKit), my code sets the ImageView to alpha 1 so the user can see that the card has been scanned.
Now: I want to implement that when the user clicks on one of the ImageViews, an alert should pop up asking the user if he is sure he wants to delete the scanned card. My problem is, I have no idea what the best practice is to get the information that the card has been tapped and how to delete it without hardcoding.
In ViewDidLoad i set the images into the ImageVies like This:
//This repeats for all 36 ImageViews
imgView1.image = UIImage(named: "Eichel_6")
imgView2.image = UIImage(named: "Eichel_7")
/*When a image is detected with ARKit, this is what happens. Basically
*it pushes the corresponding reference name to an array called
* scannedCards, handles them, and removes them afterwards.
* spielPoints = gamepoints/points, spielmodus = gamemode
*/
func updateLabel() {
//print all cards in scanned cards
for card in scannedCards {
points += (DataController.shared.spielpoints[DataController.shared.spielmodus!]![card]! * DataController.shared.multCalculator[DataController.shared.spielmodus!]!)
}
scannedCards.removeAll()
}
I am a new to coding, I would be grateful if you correct me if my code snippets are bad, beside my question. Thank you in advance.
As has already been mentioned in comments, you should use a UICollectionView for this kind of work. #Fogmeister has promised to add an answer concerning that later, so I won't do that. But I can answer the actual question, even though it's not what you should do.
From your code I can see that you probably have outlets for all your imageViews (imgView1 ... imgView36) and set each image manually. To detect taps on any of these, you could do something like this:
func viewDidLoad(){
super.viewDidLoad()
let allImageViews = [imageView1, imageView2, .... imageView36]
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTapImageView(gesture:)))
allImageViews.forEach({$0.addGestureRecognizer(tapGestureRecognizer)})
}
#objc func didTapImageView(gesture:UITapGestureRecognizer){
guard let imageView = gesture.view as? UIImageView else { return }
//Here you can put code that will happen regardless of which imageView was tapped.
imageView.alpha = 0.0
//If you need to know exactly which imageView was tapped, you can just check
if imageView == self.imageView1{
//Do stuff only for imageView1
}else if imageView == self.imageView2{
//...
}//....
}
Again, this is not very good practice. If you go for UICollectionView instead, you don't have to have outlets for all your imageViews and you don't have to create a gestureRecognizer for handling events. But still, I hope this helped you understand general gestures better.

Show or hide items by clicking button

I have four imageview contents in an XIB and a button that covers all my XIB. I want to make when the user tap the button, the first imageview is shown, the next tap is hidden and the second imageview is displayed and so on until all my imageview is shown / hidden. What would be the most efficient way to do it?
Save all your UIImageViews to an array, and current showing imageView to a variable, it may look like this:
var imageViews: [UIImageView] = []
var currentImageViewIndex = 0 {
didSet {
if currentImageViewIndex >= imageViews.count { currentImageViewIndex = 0 }
imageViews[oldValue].isHidden = true
imageViews[currentImageViewIndex].isHidden = false
}
}
func handleTap() {
currentImageViewIndex += 1
}
I suggest you use a state variable that contains an enum listing the various states (firstImageVisible, secondImage.... ) then you can have a function inside the enum that switches to the nextState (being the target of your button action) you can also easily iterate through states of an enum, check the documentation for the CaseIterable protocol. Often having a property observer (didSet) on the state is a handy place to update other parts of the UI which need to change every time the state changes.

Voting buttons with Parse in Swift

A quick overview of what I'm trying to make. I'm making an app to show my film reviews. I have a PFQueryTableviewController of which I use a custom cell. This table shows films which come from my Parse database. In each cell, there a 3 UIButtons, of which I want the user to use to vote for the film (happyVote, OkVote, sadVote). Over the top of each button is a UILabel that simply displays a count.
How I want it to work
When a user presses one of the buttons, the vote increases by 1.
When a user presses the same button again, the vote decreases by 1. Or,
If the user had pressed a different button, the vote decreases on the first button and increases on the button just pressed.
The user can only ever vote on one of the buttons.
The vote is shown by the UILabel showing the count, and by the button image changing.
See below for a visual:
This is what I've added in Parse:
So far, I've added the code to increase the vote count in Parse, in my TableViewController.swift:
#IBAction func upVoteButton(sender: AnyObject) {
let hitPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
let hitIndex = self.tableView.indexPathForRowAtPoint(hitPoint)
let object = objectAtIndexPath(hitIndex)
object!.incrementKey("UpVoteCount")
object!.saveInBackground()
self.tableView.reloadData()
}
This kind of works, except, the user can keep increasing the count, and they can vote on all 3 buttons. And it doesn't change the Button Image when pressed.
In my cellForRowAtIndexPath method, I've put:
let downVote = object!.valueForKey("DownVoteCount") as! Int
cell.downVoteLabel.text = "\(downVote)"
let middleVote = object!.valueForKey("MiddleVoteCount") as! Int
cell.middleVoteLabel.text = "\(middleVote)"
let upVote = object!.valueForKey("UpVoteCount") as! Int
cell.upVoteLabel.text = "\(upVote)"
I have searched for a while for some examples of how to figure the rest out, but can't find anything, and I'm really struggling to figure the next steps out.
Any help will be greatly appreciated, and please let me know if you need/want to see anymore of my code. Thanks
In your upVoteButton() method, you can add the other two buttons and set them button.enabled = false inside an if statement like:
if downVoteButton.enabled == true {
downVoteButton.enabled = false
} else if downVoteButton.enabled == false {
downVoteButton.enabled = True
}
And do the same with the middleVoteButton in antoher if statement or the same, whatever floats your boat, also within the other button methods with the appropriate buttons. This helps disables the buttons when pressed and then enables it when it's pressed again.
And for the image changing you can follow this.

Using iOS pan gesture to highlight buttons in grid

So far I have a grid of buttons and have attached a pan gesture recognizer to the view. I can track the events and get the location of the finger as it moves but there doesn't seem to be the equivalent of a "mouseEnter" message to use to get info about or control properties (such as the highlighting) of the other buttons I pass over.
Am I missing something? How can I accomplish, say, highlighting the buttons under the users' fingers as they pan over them? Does cocoa touch support this or must something else be done?
Thanks.
You are right, there is no such event. Also UIButton events won't help you either, because those require to actually start gesture inside. What you can do instead is to get location of the point you are currently dragging:
func panDetected(sender : MoreInformativeGestureRecognizer) {
let touchPoint = sender.locationInView(self.view)
}
And now, when you have the point, you can iterate on all the buttons you have and check if the point is inside the button:
let buttons = [UIButton]
let lastActiveButton = UIButton?
...
// Iterate through all the buttons
for button in buttons {
// Check area of the button against your touch
if CGRectContainsPoint(button.frame, touchPoint) {
// You are inside the touch area of the button
// Here, you can for example perform some action if you want, store information
// about the button so you don't do it multiple times etc.. your call :)
self.lastActiveButton = button
}
}
This way you can detect then you go in and out and do whatever you want with events. Hope it helps!
UIButton inherits from UIControl which has a number of events
Have you tried that? You can add a listener to those events, either through nib/storyboard or through code (look under discussion to see how to do this)

How to detect which image has been tapped in swift

I have created 6 UIImageViews on a ViewController, and I am later going to add TapGestureRecognizers to all of them.
I want to make it so that depending on what image has been clicked, another ViewController will open and display certain information.
For this to happen, I need to know which image has been clicked. How would I do this in Swift?
UIGestureRecognizer has property 'view' this property is the view you add it to. For this example the imageView.
func tap(gesture: UIGestureRecognizer) {
println(gesture.view!.tag) // You can check for their tag and do different things based on tag
}
let img = UIImageView()
img.userInteraction = true
img.tag = 0
img.addGestureRecognizer(UITapGestureRecognizer(self, action: "tap:"))

Resources