我花了好几个小时在网上搜索我的 UIButton 在 UICollectionView 中不起作用的解决方案。让我发疯,直到我终于找到适合我的解决方案。而且我相信这也是正确的方法:破解命中测试。这是一个比修复 UICollectionView 按钮问题更深入(双关语)的解决方案,因为它可以帮助您将点击事件发送到隐藏在阻止您的事件通过的其他视图下的任何按钮:
UIButton in cell in collection view not receiving touch up inside event
由于 SO 答案在 Objective C 中,我从那里找到了一个快速解决方案的线索:
http://khanlou.com/2018/09/hacking-hit-tests/
--
当我禁用单元格上的用户交互或我尝试的任何其他各种答案时,都没有任何效果。
我在上面发布的解决方案的美妙之处在于,您可以保留 addTarget 和选择器函数的习惯,因为它们很可能永远不会成为问题。您只需要重写一个函数来帮助触摸事件到达目的地。
解决方案为何有效:
在最初的几个小时里,我发现我的 addTarget 调用没有正确注册手势。事实证明,目标注册良好。触摸事件根本就没有到达我的按钮。
现实似乎来自我阅读的任何数量的 SO 帖子和文章,即 UICollectionView 单元旨在容纳一个动作,而不是出于各种原因的多个动作。所以你只是应该使用内置的选择动作。考虑到这一点,我相信绕过此限制的正确方法不是破解 UICollectionView 以禁用滚动或用户交互的某些方面。 UICollectionView 只是在做它的工作。 正确的方法是破解命中测试以在点击到达 UICollectionView 之前拦截点击并找出他们正在点击的项目。然后,您只需向他们正在点击的按钮发送一个触摸事件,然后让您的正常工作完成。
我的最终解决方案(来自 khanlou.com 文章)是将我的 addTarget 声明和我的选择器函数放在我喜欢的任何位置(在单元格类或 cellForItemAt 覆盖中),并在覆盖 hitTest 函数的单元格类中。
在我的单元班中,我有:
@objc func didTapMyButton(sender:UIButton!) {
print("Tapped it!")
}
和
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard isUserInteractionEnabled else { return nil }
guard !isHidden else { return nil }
guard alpha >= 0.01 else { return nil }
guard self.point(inside: point, with: event) else { return nil }
// add one of these blocks for each button in our collection view cell we want to actually work
if self.myButton.point(inside: convert(point, to: myButton), with: event) {
return self.myButton
}
return super.hitTest(point, with: event)
}
在我的单元类初始化中,我有:
self.myButton.addTarget(self, action: #selector(didTapMyButton), for: .touchUpInside)