(Je viens tout juste de commencer à utiliser Swift il y a quelques jours et je suis relativement nouveau en programmation, alors je vous en prie, gardez-moi.) J'essaie de faire apparaître des blocs aléatoires à l'écran, et l'utilisateur doit les appuyer pour les faire disparaître. J'ai pu créer les blocs, mais je ne sais pas comment les rendre réellement exploitables. Quelqu'un peut-il m'aider s'il vous plaît? Ceci est mon code jusqu'à présent:
func createBlock(){
let imageName = "block.png"
let image = UIImage(named: imageName)
let imageView = UIImageView(image: image!)
imageView.frame = CGRect(x: xPosition, y: -50, width: size, height: size)
self.view.addSubview(imageView)
UIView.animateWithDuration(duration, delay: delay, options: options, animations: {
imageView.backgroundColor = UIColor.redColor()
imageView.frame = CGRect(x: self.xPosition, y: 590, width: self.size, height: self.size)
}, completion: { animationFinished in
imageView.removeFromSuperview()
})
}
C'est le nouveau code:
func createBlock(){
let imageName = "block.png"
let image = UIImage(named: imageName)
let imageView = UIImageView(image: image!)
imageView.frame = CGRect(x: xPosition, y: -50, width: size, height: size)
self.view.addSubview(imageView)
imageView.userInteractionEnabled = true
let tapRecognizer = UITapGestureRecognizer(target: self, action: Selector("imageTapped"))
imageView.addGestureRecognizer(tapRecognizer)
func imageTapped(gestureRecognizer: UITapGestureRecognizer) {
let tappedImageView = gestureRecognizer.view!
tappedImageView.removeFromSuperview()
score += 10
}
UIView.animateWithDuration(duration, delay: delay, options: options, animations: {
imageView.backgroundColor = UIColor.redColor()
imageView.frame = CGRect(x: self.xPosition, y: 590, width: self.size, height: self.size)
}, completion: { animationFinished in
imageView.removeFromSuperview()
})
}
Une fois que vous avez créé la vue, vous devez définir sa propriété userInteractionEnabled sur true. Ensuite, vous devez y attacher un geste.
imageView.userInteractionEnabled = true
//now you need a tap gesture recognizer
//note that target and action point to what happens when the action is recognized.
let tapRecognizer = UITapGestureRecognizer(target: self, action: Selector("imageTapped:"))
//Add the recognizer to your view.
imageView.addGestureRecognizer(tapRecognizer)
Maintenant, vous avez toujours besoin de la fonction, dans ce cas imageTapped :, qui est l'endroit où l'action se produit lorsque le geste est reconnu. Le geste qui a été reconnu sera envoyé en tant qu'argument et vous pourrez déterminer quelle imageView a été exploitée à partir de la propriété d'affichage des gestes.
func imageTapped(gestureRecognizer: UITapGestureRecognizer) {
//tappedImageView will be the image view that was tapped.
//dismiss it, animate it off screen, whatever.
let tappedImageView = gestureRecognizer.view!
}
Dans Swift 3.0:
imvEditName.isUserInteractionEnabled = true
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
imvEditName.addGestureRecognizer(tapRecognizer)
Et la méthode cible:
func imageTapped(sender: UIImageView) {
print("image tapped")
}
Ma réponse précédente reste exacte pour l'ajout d'un identificateur de frappe à un UIImageView, mais cela ne suffit pas pour une vue animée. Si vous créez réellement un jeu, vous voudrez probablement vous familiariser avec SpriteKit, car il est littéralement conçu à cet effet. Cependant, ceci peut être accompli avec un UIKit normal. J'ai testé deux approches, qui fonctionnent toutes les deux.
_ {Les deux approches fonctionnent beaucoup mieux sur un appareil réel que dans le simulateur} _
Approche 1, plus simple mais un peu moins précise jusqu'à un dixième de seconde plus lent dans mes tests.} _
Au lieu d'ajouter un geste de tapotement à UIImageView, ajoutez le geste à la vue d'ensemble. Conservez une référence à vos blocs dans une propriété de tableau et vérifiez si des blocs sont interceptés par le tapotement.
class ViewController: UIViewController {
let size = CGFloat(40)
let xPosition = CGFloat(14)
let options = UIViewAnimationOptions.Autoreverse
var blocks = [UIImageView]()
override func viewDidLoad() {
super.viewDidLoad()
// Adding recognizer to the whole view.
let tapRecognizer = UITapGestureRecognizer(target: self, action: Selector("screenTapped:"))
view.addGestureRecognizer(tapRecognizer)
blocks.append(createBlock())
}
//changed to return the created block so it can be stored in an array.
func createBlock() -> UIImageView {
let imageName = "block.png"
let image = UIImage(named: imageName)
let imageView = UIImageView(image: image!)
imageView.frame = CGRect(x: xPosition, y: -40, width: size, height: size)
self.view.addSubview(imageView)
UIView.animateWithDuration(2, delay: 0.0, options: options, animations: {
imageView.backgroundColor = UIColor.redColor()
imageView.frame = CGRect(x: self.xPosition, y: 590, width: self.size, height: self.size)
}, completion: { animationFinished in
imageView.removeFromSuperview()
self.blocks.append(self.createBlock())
})
return imageView
}
func screenTapped(gestureRecognizer: UITapGestureRecognizer) {
let tapLocation = gestureRecognizer.locationInView(view)
//This is to keep track of the blocks to remove from the array.
//If you remove them as you iterate the array, and you have more than
//one block to remove, you may end up removing the wrong block
//or with an index out of bounds.
var removeBlocks = [Int]()
for (index, block) in enumerate(blocks) {
//this is the frame of the view as we see it on screen.
//unfortunately block.frame is not where we see it making a recognizer
//on the block itself not work.
if block.layer.presentationLayer().frame.contains(tapLocation) {
//Then this block was clicked.
block.removeFromSuperview()
removeBlocks.append(index)
}
}
//get the indexes ro remove backwards so we are removing from
//back to front.
for index in removeBlocks.reverse() {
blocks.removeAtIndex(index)
}
}
}
Approche 2, performances optimales en dehors de SpriteKit
Dans l'approche deux, vous sous-classe UIView et définissez votre vue principale à la place de UIView. Il vous suffit de remplacer une seule méthode. Je stocke le tableau de blocs dans la vue pour plus de commodité.
D'abord le TouchView.
import UIKit
class TouchView: UIView {
var blocks = [UIImageView]()
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
// ignoring multiple touches for now
if touches.count == 1 {
if let touch = touches.first as? UITouch {
let touchLocation = touch.locationInView(self)
//This is to keep track of the blocks to remove from the array.
//If you remove them as you iterate the array, and you have more than
//one block to remove, you may end up removing the wrong block
//or with an index out of bounds.
var removeBlocks = [Int]()
for (index, block) in enumerate(blocks) {
//this is the frame of the view as we see it on screen.
//unfortunately block.frame is not where we see it making a recognizer
//on the block itself not work.
if block.layer.presentationLayer().frame.contains(touchLocation) {
//Then this block was clicked.
block.removeFromSuperview()
removeBlocks.append(index)
}
}
//get the indexes ro remove backwards so we are removing from
//back to front.
for index in removeBlocks.reverse() {
blocks.removeAtIndex(index)
}
}
}
}
}
Maintenant, le ViewController ressemblerait à ceci:
import UIKit
class ViewController: UIViewController {
let size = CGFloat(40)
let xPosition = CGFloat(14)
let options = UIViewAnimationOptions.Autoreverse
var blocks = [UIImageView]()
// computed get only property for conveniece of accessing block array
var touchView:TouchView {
get {
return self.view as! TouchView
}
}
override func viewDidLoad() {
super.viewDidLoad()
touchView.blocks.append(createBlock())
// Do any additional setup after loading the view, typically from a nib.
}
func createBlock() -> UIImageView {
let imageName = "block.png"
let image = UIImage(named: imageName)
let imageView = UIImageView(image: image!)
imageView.frame = CGRect(x: xPosition, y: -40, width: size, height: size)
self.view.addSubview(imageView)
UIView.animateWithDuration(2, delay: 0.0, options: options, animations: {
imageView.backgroundColor = UIColor.redColor()
imageView.frame = CGRect(x: self.xPosition, y: 590, width: self.size, height: self.size)
}, completion: { animationFinished in
imageView.removeFromSuperview()
self.touchView.blocks.append(self.createBlock())
})
return imageView
}
}
Dans mes tests, cela semble assez bien fonctionner, même avec des "blocs" animés rapidement. Encore une fois, si vous envisagez de créer un jeu à part entière, vous devriez vraiment regarder SpriteKit. Il existe un tutoriel très simple ici qui devrait vous aider à démarrer. Si vous pouvez supprimer la réponse acceptée de ma réponse précédente, cela aiderait les autres à ne pas se laisser guider par le mauvais chemin, à moins qu'ils ne cherchent seulement à ajouter un geste à un UIImageView non déplacé.
Par défaut, l’interaction utilisateur de la vue image n’est pas activée; veillez donc à la désactiver.
let myImageView = UIImageView()
myImageView.isUserInteractionEnabled = true
Au lieu d'utiliser une UIImageView
, vous pouvez essayer d'utiliser une Custome UIButton
et remplacer l'image du bouton par défaut par la vôtre. Par conséquent, vous n'avez pas besoin d'ajouter UITapGestureRecognizer
pour chaque UIImageView. L'approche de @JeremyPope est en réalité plus efficace que celle-ci.
Le traitement UIButton
est assez simple, sa sous-classe est UIControl
. Il existe donc des propriétés telles que hide
et enabled
et vous pouvez les manipuler comme vous le souhaitez.
Ce que vous devez faire est de créer UIButton
par programme, tout comme vous, vous créez ainsi UIImageView
. La façon de les créer est similaire à UIImageView
, lisez plus sur créez UIButton par programme dans Swift .
L'image ci-dessous montre à quoi ressemble une UIButton
personnalisée.
Laissez des commentaires si vous avez besoin de plus d'informations.