微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

自定义 UIView 中的 UITapGestureRecognizer 不起作用

如何解决自定义 UIView 中的 UITapGestureRecognizer 不起作用

Swift 5/Xcode 12.4

我为我的自定义 MarkerView 创建了一个 xib 文件 - 布局非常简单:

- View
-- StackView
--- DotLabel
--- NameLabel
认情况下,

ViewStackView 在检查器中都设置为“启用用户交互”。 DotLabelNameLabel 不是,但勾选它们的框似乎并没有真正改变任何东西。

在运行时,我在 ViewController 中创建 MarkerViews(仅用于测试目的,只有一个 atm)并将它们添加到已经包含图像的 ScrollView 中(这有效):

override func viewDidAppear(_ animated: Bool) {
    createMarkers()
    setUpMarkers()
}

private func createMarkers() {
    let marker = MarkerView()
    marker.setUp("Some Text")
    markers.append(marker)
    scrollView.addSubview(marker)
    marker.alpha = 0.0
}

private func setUpMarkers() {
    for (i,m) in markers.enumerated() {
        m.frame.origin = CGPoint(x: (i+1)*100,y: (i+1)*100)
        m.alpha = 1.0
    }
}

这些 MarkerViews 应该是可点击的,所以我添加一个 UITapGestureRecognizer链接函数从未被调用。这是我的完整 MarkerView:

class MarkerView: UIView {
    @IBOutlet weak var stackView: UIStackView!
    @IBOutlet weak var dotLabel: UILabel!
    @IBOutlet weak var nameLabel: UILabel!
    
    let nibName = "MarkerView"
    var contentView:UIView?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() {
        guard let view = loadViewFromNib() else { return }
        view.frame = self.bounds
        self.addSubview(view)
        contentView = view
        
        let gesture = UITapGestureRecognizer(target: self,action: #selector(self.clickedMarker))
        self.addGestureRecognizer(gesture)
    }
    func loadViewFromNib() -> UIView? {
        let bundle = Bundle(for: type(of: self))
        let nib = UINib(nibName: nibName,bundle: bundle)
        return nib.instantiate(withOwner: self,options: nil).first as? UIView
    }
    
    func setUp(_ name:String) {
        nameLabel.text = name
        nameLabel.sizetoFit()
        stackView.sizetoFit()
    }
    
    @objc private func clickedMarker() {
        print("Clicked Marker!")
    }
}

其他问题建议在添加手势识别器之前添加self.isUserInteractionEnabled = true。我什至为 StackView 和两个标签启用了它,还尝试将手势识别器添加到 ScrollView,但没有任何帮助。

为什么手势识别器不起作用,我该如何解决这个问题?

编辑:根据 sweeper 的建议,我的代码现在如下所示:

class MarkerView: UIView,UIGestureRecognizerDelegate {
    .....
    func commonInit() {
        guard let view = loadViewFromNib() else { return }
        view.frame = self.bounds
        let gesture = UITapGestureRecognizer(target: self,action: #selector(self.clickedMarker))
        gesture.delegate = self
        self.isUserInteractionEnabled = true
        self.addGestureRecognizer(gesture)
        self.addSubview(view)
        contentView = view
    }
    .....
    func gestureRecognizer(_: UIGestureRecognizer,_ otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        print("gestureRecognizer")
        return true
    }
}

“gestureRecognizer”永远不会打印到控制台。

解决方法

@Sweeper linked 问题的已接受答案下方的评论之一给出了一个很好的提示:

内容视图的大小(记录)是多少?

print(self.frame.size)
print(contentView.frame.size)

都在我的应用中打印了 (0.0,0.0)UITapGestureRecognizer 附加到 self,因此即使它有效,也没有您可以点击的区域来识别点击。

解决方案:设置 UIView 附加到的 UITapGestureRecognizer 的大小:

stackView.layoutIfNeeded()
stackView.sizeToFit()
self.layoutIfNeeded()
self.sizeToFit()

对我不起作用,之后尺寸仍然是 (0.0,0.0)。相反,我直接设置了 self 的大小:

self.frame.size = stackView.frame.size

这也设置了 contentView 的大小(因为它是 MarkerView 的孩子)但当然也需要正确设置 stackView 的大小。您可以自己添加孩子的宽度/高度(包括间距/边距)或简单地调用:

stackView.layoutIfNeeded()
stackView.sizeToFit()

完成的代码:

func setUp(_ name:String) {
    nameLabel.text = name
    //nameLabel.sizeToFit() //Not needed anymore
    stackView.layoutIfNeeded() //Makes sure that the labels already use the proper size after updating the text
    stackView.sizeToFit()
    self.frame.size = stackView.frame.size

    let gesture = UITapGestureRecognizer(target: self,action: #selector(self.onClickStackView))
    self.addGestureRecognizer(gesture)
}

规格:

  1. 不需要 delegate 和覆盖 func gestureRecognizer(_: UIGestureRecognizer,_ otherGestureRecognizer: UIGestureRecognizer) -> Bool 总是返回 true,这可能是一种替代方法,但我没有设法让那个版本工作 - 函数是从来没有打过电话。如果有人知道如何操作,请随时将其作为替代解决方案发布。
  2. 一旦父视图知道它的大小,就必须附加 UITapGestureRecognizer,这在 commonInit 中没有,因为标签的文本和所有内容的大小尚未在那里设置.可以在附加识别器后添加更多文本,但如果使用上述代码,则超出原始长度(附加识别器时)的所有内容都将无法点击。
  3. 使用父视图的背景颜色(stackView 的被忽略),但可以简单地将其设置为透明颜色。
  4. 将手势识别器附加到 stackView 而不是 self 的工作方式相同。您甚至可以使用 UILabel 但它们的“启用用户交互”在默认情况下是关闭的 - 首先在“属性检查器”(“查看”部分中的复选框)或代码中启用它({{1 }}).

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。