Vous cherchez à ajouter un geste de toucher à un tableau de UIView
- sans succès. Tap ne semble pas être reconnu à ce stade.
Dans le code (extrait) ci-dessous:
Avoir une série de PlayingCardViews
(chacun un UIView
) affiché sur la vue principale.
Réunis sous forme de tableau: cardView
.
Il faut pouvoir appuyer sur chaque PlayingCardView
indépendamment (et ensuite pouvoir identifier celui qui a été touché).
@IBOutlet private var cardView: [PlayingCardView]! override func viewDidLoad() { super.viewDidLoad() let tap = UITapGestureRecognizer(target: self, action: #selector(tapCard(sender: ))) for index in cardView.indices { cardView[index].isUserInteractionEnabled = true cardView[index].addGestureRecognizer(tap) cardView[index].tag = index } } @objc func tapCard (sender: UITapGestureRecognizer) { if sender.state == .ended { let cardNumber = sender.view.tag print("View tapped !") } }
4 Réponses :
Vous avez besoin de
for index in cardView.indices { let tap = UITapGestureRecognizer(target: self, action: #selector(tapCard(sender: )))
Pas besoin de vérifier l'état ici car la méthode avec ce type de geste n'est appelée qu'une seule fois, chaque vue doit également avoir un robinet séparé, alors créez-la dans la boucle for
@objc func tapCard (sender: UITapGestureRecognizer) { let clickedView = cardView[sender.view!.tag] print("View tapped !" , clickedView ) }
Merci @sh_khan. J'essaierai cela dès que je pourrai obtenir la fonction «tapCard» pour être appelée par le geste du robinet.
Merci @sh_khan. Cela semble fonctionner en effet ... testez ici et confirmera sous peu. Aussi, bref à part: où est le meilleur endroit pour avoir la boucle for pour créer les gestes de tap: dans viewDidLoad (comme ci-dessus) ou dans un didSet dans la déclaration de cardView? Est-ce que cela fait une différence ? Un est-il plus approprié? (revenant sous peu pour confirmer si j'ai pu réparer selon votre solution)
Les deux cas fonctionneront, mais je recommande viewDidLoad
Testé et semble avoir fonctionné, @sh_khan. Merci !
let tap = UITapGestureRecognizer(target: self, action: #selector(didTapCard(sender: ))) for (index, view) in cardView.enumerated() { view.isUserInteractionEnabled = true view.addGestureRecognizer(tap) view.tag = index } And then in your didTapCard func you'll need to check the tag.
Merci. Mais étant donné le commentaire de @sh_khan ci-dessous, la création de tap ne serait-elle pas à l'intérieur de la boucle for?
En auriez-vous besoin pour le créer plusieurs fois? Si toutes les vues pointent vers le même sélecteur de gestes et que vous vérifiez à l'intérieur de votre sélecteur quelle est la balise ...
Vous pouvez essayer de transmettre le contrôleur de vue en tant que paramètre aux vues afin qu'elles puissent appeler une fonction sur le contrôleur de vue parent à partir de la vue. Pour réduire la mémoire, vous pouvez utiliser des protocoles. e.x
protocol testViewControllerDelegate: class { func viewTapped(view: UIView) } class testClass: testViewControllerDelegate { @IBOutlet private var cardView: [PlayingCardView]! override func viewDidLoad() { super.viewDidLoad() for cardView in self.cardView { cardView.fatherVC = self } } func viewTapped(view: UIView) { // the view that tapped is passed ass parameter } } class PlayingCardView: UIView { var fatherVC: testViewControllerDelegate? override func awakeFromNib() { super.awakeFromNib() let gr = UITapGestureRecognizer(target: self, action: #selector(self.viewDidTap)) self.addGestureRecognizer(gr) } @objc func viewDidTap() { fatherVC?.viewTapped(view: self) } }
Merci, jettera un œil. Également testé la solution de @sh_khan et semble fonctionner.
Je ne recommanderai pas la réponse sélectionnée. Parce que créer un tableau de tapGesture n'a pas de sens pour moi dans la boucle. Mieux vaut ajouter un geste dans PlaycardView.
Au lieu de cela, une telle disposition doit être conçue en utilisant UICollectionView. Si vous avez besoin d'une mise en page personnalisée et que vous souhaitez utiliser scrollView ou même UIView, la meilleure approche consiste à créer un seul reconnaissance de gestes et à l'ajouter à la supervision.
En utilisant le geste du toucher, vous pouvez obtenir l'emplacement du toucher, puis vous pouvez obtenir la vue sélectionnée en utilisant cet emplacement.
Veuillez vous référer à l'exemple ci-dessous:
import UIKit class PlayCardView: UIView { override init(frame: CGRect) { super.init(frame: frame) backgroundColor = UIColor.red } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) backgroundColor = UIColor.red } } class SingleTapGestureForMultiView: UIViewController { var viewArray: [UIView]! var scrollView: UIScrollView! override func viewDidLoad() { super.viewDidLoad() scrollView = UIScrollView(frame: UIScreen.main.bounds) view.addSubview(scrollView) let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapGetsure(_:))) scrollView.addGestureRecognizer(tapGesture) addSubviews() } func addSubviews() { var subView: PlayCardView let width = UIScreen.main.bounds.width; let height = UIScreen.main.bounds.height; let spacing: CGFloat = 8.0 let noOfViewsInARow = 3 let viewWidth = (width - (CGFloat(noOfViewsInARow+1) * spacing))/CGFloat(noOfViewsInARow) let viewHeight = (height - (CGFloat(noOfViewsInARow+1) * spacing))/CGFloat(noOfViewsInARow) var yCordinate = spacing var xCordinate = spacing for index in 0..<20 { subView = PlayCardView(frame: CGRect(x: xCordinate, y: yCordinate, width: viewWidth, height: viewHeight)) subView.tag = index xCordinate += viewWidth + spacing if xCordinate > width { xCordinate = spacing yCordinate += viewHeight + spacing } scrollView.addSubview(subView) } scrollView.contentSize = CGSize(width: width, height: yCordinate) } @objc func tapGetsure(_ gesture: UITapGestureRecognizer) { let location = gesture.location(in: scrollView) print("location = \(location)") var locationInView = CGPoint.zero let subViews = scrollView.subviews for subView in subViews { //check if it subclass of PlayCardView locationInView = subView.convert(location, from: scrollView) if subView.isKind(of: PlayCardView.self) { if subView.point(inside: locationInView, with: nil) { // this view contains that point print("Subview at \(subView.tag) tapped"); break; } } } } }
Merci pour la solution alternative, @ankur.
Alors, la fonction
tapCard
est-elle appelée? Btw vous n'utilisez pas encore la propriétécardNumber
pour quoi que ce soit.Correct @ DávidPásztor: la fonction 'tapCard' n'est pas appelée (c'est-à-dire que lorsque je tape sur n'importe quelle PlayingCardView sur IB, rien n'est imprimé sur la console. En ce qui concerne 'cardNumber', vous avez également raison, pas encore utilisé mais avez l'intention de le faire plus tard.
Vous ne pouvez pas être sûr que la fonction n'est pas appelée simplement par l'instruction
print
non exécutée, puisque vous l'avez imbriquée dans une instructionif
:) Vous devez utiliser le débogueur pour vérifier si la fonction est réellement appelée ou non (ou mettre une instruction d'impression en dehors de l'instructionif
), mais cette instructionif
semble de toute façon inutile.Suppression de l'instruction if et conservation de l'impression uniquement dans la fonction. Toujours rien d'imprimé sur la console.
le robinet dans votre cas actuel sera ajouté à la dernière vue uniquement