web-dev-qa-db-fra.com

Comment rendre un UIImageView exploitable et le faire faire quelque chose? (Rapide)

(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()


    })



}
6
Leonard Parisi

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!
}
32
Jeremy Pope

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é.

2
Jeremy Pope

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
1
user7953705

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.

enter image description here

Laissez des commentaires si vous avez besoin de plus d'informations.

1
Xinyang Li