0

我发现了很多关于不接收触摸事件的类似问题,我知道在某些情况下,可能需要编写自定义的 hitTest 函数——但我还读到响应者链将遍历层次结构中的视图和视图控制器——我不明白为什么我的实现需要自定义 hitTest。

我正在寻找解释和/或指向解释如何测试响应者链的文档的链接。此问题出现在 Xcode 10.2.1 中。

我的场景(我没有使用情节提要):

  • 我有一个 mainViewController,它提供了一个带有 ImageView 和一些标签的全屏视图。我已将 TapGestureRecognizers 附加到 ImageView 和其中一个标签上——它们都可以正常工作。
  • 当我点击标签时,我添加了一个子视图控制器,它作为主视图控制器的子视图。视图被限制为仅覆盖屏幕的右半部分。
  • 子 viewController 包含一个垂直堆栈视图,其中包含 3 个排列的子视图。
  • 每个排列的Subview 都包含一个 Label 和一个水平 StackView。
  • 水平 stackView 的每一个都包含一个带有标签的视图作为子视图。
  • 子视图中的 Label 将其 isUserInteractionEnabled 标志设置为 True 并添加 TapGestureRecognizer。
  • 这些是子 ViewController 中唯一设置了“isUserInteractionEnabled”的对象。

标签嵌套得相当深,但由于这是直接的父/子层次结构(与属于 NavigationController 的 2 个视图相反),我希望标签位于正常的响应程序链中并正常运行。Stack View 会改变这种行为吗?我是否需要在某些视图上将“isUserInteractionEnabled”值显式设置为 False?有没有办法可以将日志记录添加到 ResponderChain,以便我可以查看它检查了哪些视图并找出它被阻止的位置?

在阅读了这篇 StackOverflow 帖子后,我尝试在 viewDidLayoutSubviews() 中添加我的手势识别器,而不是如下所示 - 但它们仍然没有收到点击事件。

提前感谢任何可以提供建议或帮助的人。

这是不响应我的点击事件的标签的代码以及它应该调用的点击事件:

    func makeColorItem(colorName:String, bgColor:UIColor, fgColor:UIColor) -> UIView {
    let colorNumber:Int = colorLabelDict.count
    let colorView:UIView = {
        let v = UIView()
        v.tag = 700 + colorNumber
        v.backgroundColor = .clear
        v.contentMode = .center
        return v
    }()
    self.view.addSubview(colorView)
    let tapColorGR:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapColor))
    let colorChoice: UILabel = {
        let l = UILabel()
        l.tag = 700 + colorNumber
        l.isUserInteractionEnabled = true
        l.addGestureRecognizer(tapColorGR)
        l.text = colorName
        l.textAlignment = .center
        l.textColor = fgColor
        l.backgroundColor = bgColor
        l.font = UIFont.systemFont(ofSize: 24, weight: .bold)
        l.layer.borderColor = fgColor.cgColor
        l.layer.borderWidth = 1
        l.layer.cornerRadius = 20
        l.layer.masksToBounds = true
        l.adjustsFontSizeToFitWidth = true
        l.translatesAutoresizingMaskIntoConstraints = false
        l.widthAnchor.constraint(equalToConstant: 100)
        return l
    }()
    colorView.addSubview(colorChoice)
    colorChoice.centerXAnchor.constraint(equalTo: colorView.centerXAnchor).isActive = true
    colorChoice.centerYAnchor.constraint(equalTo: colorView.centerYAnchor).isActive = true
    colorChoice.heightAnchor.constraint(equalToConstant: 50).isActive = true
    colorChoice.widthAnchor.constraint(equalToConstant: 100).isActive = true
    colorLabelDict[colorNumber] = colorChoice
    return colorView
}

    @objc func tapColor(sender:UITapGestureRecognizer) {
    print("A Color was tapped...with tag:\(sender.view?.tag ?? -1)")
    if let cn = sender.view?.tag {
        colorNumber = cn
        let v = colorLabelDict[cn]
        if let l = (v?.subviews.first as? UILabel) {
            print("The \(l.text) label was tapped.")
        }
    }
}
4

1 回答 1

1

看起来您没有获得点击识别的主要原因是因为您将 a 添加UILabel为 a 的子视图UIView,但您没有给予UIView任何限制。所以视图最终的宽度和高度为零,并且标签存在于视图边界之外

在没有看到所有代码的情况下,看起来您不需要保存标签的额外视图。

看看这个......它将向主视图添加一个垂直堆栈视图 - 以 X 和 Y 为中心 - 并将“colorChoice”标签添加到堆栈视图:

class TestViewController: UIViewController {
    
    let stack: UIStackView = {
        let v = UIStackView()
        v.axis = .vertical
        v.spacing = 4
        return v
    }()
    
    var colorLabelDict: [Int: UIView] = [:]
    

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let v1 = makeColorLabel(colorName: "red", bgColor: .red, fgColor: .white)
        let v2 = makeColorLabel(colorName: "green", bgColor: .green, fgColor: .black)
        let v3 = makeColorLabel(colorName: "blue", bgColor: .blue, fgColor: .white)

        [v1, v2, v3].forEach {
            stack.addArrangedSubview($0)
        }

        stack.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(stack)
        
        NSLayoutConstraint.activate([
            stack.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            stack.centerYAnchor.constraint(equalTo: view.centerYAnchor),
        ])
    }
    
    func makeColorLabel(colorName:String, bgColor:UIColor, fgColor:UIColor) -> UILabel {
        let colorNumber:Int = colorLabelDict.count
        // create tap gesture recognizer
        let tapColorGR:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapColor))
        let colorChoice: UILabel = {
            let l = UILabel()
            l.tag = 700 + colorNumber
            l.addGestureRecognizer(tapColorGR)
            l.text = colorName
            l.textAlignment = .center
            l.textColor = fgColor
            l.backgroundColor = bgColor
            l.font = UIFont.systemFont(ofSize: 24, weight: .bold)
            l.layer.borderColor = fgColor.cgColor
            l.layer.borderWidth = 1
            l.layer.cornerRadius = 20
            l.layer.masksToBounds = true
            l.adjustsFontSizeToFitWidth = true
            l.translatesAutoresizingMaskIntoConstraints = false
            // default .isUserInteractionEnabled for UILabel is false, so enable it
            l.isUserInteractionEnabled = true
            return l
        }()
        NSLayoutConstraint.activate([
            // label height: 50, width: 100
            colorChoice.heightAnchor.constraint(equalToConstant: 50),
            colorChoice.widthAnchor.constraint(equalToConstant: 100),
        ])
        // assign reference to this label in colorLabelDict dictionary
        colorLabelDict[colorNumber] = colorChoice
        // return newly created label
        return colorChoice
    }
    
    @objc func tapColor(sender:UITapGestureRecognizer) {
        print("A Color was tapped...with tag:\(sender.view?.tag ?? -1)")
        // unwrap the view that was tapped, make sure it's a UILabel
        guard let tappedView = sender.view as? UILabel else {
            return
        }
        let cn = tappedView.tag
        let colorNumber = cn
        print("The \(tappedView.text ?? "No text") label was tapped.")
    }
}

运行结果:

在此处输入图像描述

这些是 3UILabel秒,点击每个会触发tapColor()func,将其打印到调试控制台:

A Color was tapped...with tag:700
The red label was tapped.
A Color was tapped...with tag:701
The green label was tapped.
A Color was tapped...with tag:702
The blue label was tapped.
于 2020-09-09T16:58:39.307 回答