【问题标题】:Swift - How to add tap gesture to array of UIViews?Swift - 如何将点击手势添加到 UIViews 数组?
【发布时间】:2019-01-21 14:57:15
【问题描述】:

希望将点击手势添加到 UIViews 数组中 - 没有成功。在此阶段似乎无法识别 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 !")
    }
}

【问题讨论】:

  • 那么tapCard 函数是否被调用了?顺便说一句,您还没有使用 cardNumber 属性。
  • 正确@DávidPásztor:'tapCard' 函数未被调用(即,当我在 IB 上点击任何 PlayingCardView 时,控制台上没有打印任何内容。关于 'cardNumber',您也是正确的,尚未使用但打算以后再说。
  • 你不能确定函数没有被print 语句没有被执行,因为你将它嵌套在if 语句中:) 你应该使用调试器来检查函数实际上是否被调用(或在if 语句之外放置一个打印语句),但if 语句似乎是不必要的。
  • 删除了 if 语句,只保留了函数中的 print。仍然没有打印到控制台。
  • 您当前案例中的点击将仅添加到最后一个视图中

标签: ios swift uitapgesturerecognizer


【解决方案1】:

你需要

@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: )))

【讨论】:

  • 谢谢@sh_khan。只要我可以通过点击手势调用“tapCard”函数,就会尝试这样做。
  • 谢谢@sh_khan。这似乎确实有效......在这里测试并将很快确认。另外,顺便说一句:在哪里有 for 循环创建点击手势的最佳位置:在 viewDidLoad (如上)或 cardView 声明中的 didSet 中?这有什么不同吗 ?一个更合适吗? (很快恢复以确认我是否能够按照您的解决方案进行修复)
  • 两种情况都可以,但我推荐viewDidLoad
  • 经过测试,似乎有效,@sh_khan。谢谢!
【解决方案2】:

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

相反,应使用 UICollectionView 设计此类布局。如果您需要自定义布局并且想要使用滚动视图甚至 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;
                }
            }

        }

    }

}

【讨论】:

  • 感谢@ankur 提供替代解决方案。
【解决方案3】:

您可以尝试将视图控制器作为参数传递给视图,以便它们可以从视图调用父视图控制器上的函数。要减少内存,您可以使用协议。例如

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

【讨论】:

  • 谢谢,去看看。还测试了来自@sh_khan 的解决方案,似乎有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-20
  • 1970-01-01
  • 1970-01-01
  • 2016-09-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多