簡體   English   中英

自定義 UIView 中的 UITapGestureRecognizer 不起作用

[英]UITapGestureRecognizer in custom UIView doesn't work

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但鏈接的 function 永遠不會被調用。 這是我完整的 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鏈接的問題的已接受答案下方的評論之一給出了一個很好的提示:

內容視圖的大小(記錄它)是多少?

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

在我的應用程序中都打印(0.0, 0.0) UITapGestureRecognizer附加到self ,因此即使它有效,也根本沒有可以點擊的區域讓它識別點擊。

解決方案:設置UITapGestureRecognizer附加到的UIView的大小:

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 ,這可能是一個替代方案,但我沒有設法讓那個版本工作 - function 從來沒有叫。 如果有人知道該怎么做,請隨時將其發布為替代解決方案。
  2. 一旦父視圖知道它的大小,就必須附加UITapGestureRecognizer ,這在commonInit中並不常見,因為標簽的文本和所有內容的大小還沒有在那里設置。 可以在附加識別器后添加更多文本,但如果使用上述代碼,則超出原始長度(在附加識別器時)的所有內容都將不可點擊。
  3. 使用父視圖的背景顏色(忽略stackView的),但可以簡單地將其設置為透明顏色。
  4. 將手勢識別器附加到stackView而不是self的工作方式相同。 您甚至可以使用UILabel ,但默認情況下它們的“用戶交互已啟用”處於關閉狀態 - 首先在“屬性檢查器”(“視圖”部分中的復選框)或代碼( myLabel.isUserInteractionEnabled = true )中啟用它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM