如何解决自定义 UIView 中的 UITapGestureRecognizer 不起作用
Swift 5/Xcode 12.4
我为我的自定义 MarkerView
创建了一个 xib 文件 - 布局非常简单:
- View
-- StackView
--- DotLabel
--- NameLabel
默认情况下,View
和 StackView
在检查器中都设置为“启用用户交互”。 DotLabel
和 NameLabel
不是,但勾选它们的框似乎并没有真正改变任何东西。
在运行时,我在 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,但没有任何帮助。
为什么手势识别器不起作用,我该如何解决这个问题?
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)
}
规格:
- 不需要
delegate
和覆盖func gestureRecognizer(_: UIGestureRecognizer,_ otherGestureRecognizer: UIGestureRecognizer) -> Bool
总是返回true
,这可能是一种替代方法,但我没有设法让那个版本工作 - 函数是从来没有打过电话。如果有人知道如何操作,请随时将其作为替代解决方案发布。 - 一旦父视图知道它的大小,就必须附加
UITapGestureRecognizer
,这在commonInit
中没有,因为标签的文本和所有内容的大小尚未在那里设置.可以在附加识别器后添加更多文本,但如果使用上述代码,则超出原始长度(附加识别器时)的所有内容都将无法点击。 - 使用父视图的背景颜色(
stackView
的被忽略),但可以简单地将其设置为透明颜色。 - 将手势识别器附加到
stackView
而不是self
的工作方式相同。您甚至可以使用UILabel
但它们的“启用用户交互”在默认情况下是关闭的 - 首先在“属性检查器”(“查看”部分中的复选框)或代码中启用它({{1 }}).
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。