问题描述
我发现了很多关于不接收触摸事件的类似问题,并且我了解在某些情况下,可能需要编写自定义的hitTest函数-但我还阅读到响应者链将遍历层次结构中的视图和viewControllers -而且我不明白为什么我的实施需要自定义hitTest。
我正在寻找说明和/或指向文档的链接,以解释如何测试响应者链。 Xcode 10.2.1中出现此问题。
我的情况(我不使用情节提要):
- 我有一个mainViewController,它提供了一个全屏视图以及一个ImageView和一些Labels。我已将TapGestureRecognizers附加到ImageView和标签之一-它们都可以正常工作。
- 当我点击标签时,我添加了一个子viewController,该视图作为mainViewController的子视图。该视图被限制为仅覆盖屏幕的右半部分。
- 子viewController包含一个垂直的堆栈视图,该视图包含3个splittedSubviews。
- 每个locatedSubview包含一个Label和一个水平StackView。
- 每个水平stackView都包含一个带有标签的视图作为子视图。
- 子视图中的Label将isUserInteractionEnabled标志设置为True,并添加TapGestureRecognizer。
- 这些是子级ViewController中唯一设置了“ isUserInteractionEnabled”的对象。
Label的嵌套非常深,但是由于这是直接的父级/子级层次结构(与属于NavigationController的2个视图相对),我希望Label处于正常的响应者链中并正常运行。堆栈视图是否改变了这种行为?我是否需要在某些视图上将'isUserInteractionEnabled'值显式设置为False?有什么方法可以将日志记录添加到ResponderChain中,以便查看检查的视图并找出被阻止的位置?
阅读this StackOverflow post后,我尝试在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.")
}
}
}
解决方法
您似乎没有被水龙头识别的主要原因似乎是因为您要添加UILabel
作为UIView
的子视图,但您并未给出{{1} }任何约束。因此,视图的宽度和高度为零,并且标签位于视图的边界之外。
没有看到所有代码,就好像您不需要带有标签的额外视图。
看看这个...它将在主视图中添加一个垂直的堆栈视图(以X和Y为中心),并在堆栈视图中添加“ colorChoice”标签:
UIView
运行结果:
这是3个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.")
}
}
,点击每个将触发UILabel
函数,将其打印到调试控制台:
tapColor()