Swift - 如何将点击手势添加到 UIView 数组?

Swift - How to add tap gesture to array of UIViews?

希望将点击手势添加到 UIView 数组 - 但没有成功。 Tap 似乎在这个阶段无法被识别。

在下面的代码(摘录)中: 在主视图上显示一系列 PlayingCardViews(每个 UIView)。 汇集为一个数组:cardView。 需要能够独立地点击每个 PlayingCardView(然后能够识别被点击的是哪一个)。

@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 !")
    }
}

你需要

@objc func tapCard (sender: UITapGestureRecognizer) { 
     let clickedView = cardView[sender.view!.tag] 
     print("View tapped !" , clickedView ) 
}

这里不需要检查状态,因为这种手势类型的方法只被调用一次,而且每个视图都应该有一个单独的点击,所以在 for 循环中创建它

for index in cardView.indices  { 
   let tap = UITapGestureRecognizer(target: self, action: #selector(tapCard(sender: )))

您可以尝试将视图控制器作为参数传递给视图,以便它们可以从视图调用父视图控制器上的函数。要减少内存,您可以使用协议。 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 {
        
        weak 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)
        }
    }

我不会推荐所选答案。因为在循环中创建一个 tapGesture 数组对我来说没有意义。最好在 PlaycardView 中添加手势。

相反,这种布局应该使用 UICollectionView 来设计。如果万一您需要自定义布局并且想要使用 scrollView 甚至 UIView,那么更好的方法是创建单个手势识别器并添加到超级视图。

使用点击手势,您可以获得点击的位置,然后您可以使用该位置获取 selectedView。

请参考下面的例子:

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;
                }
            }

        }

    }

}