UICollectionView 的 UICollectionReusableView 防止/阻止对 UICollectionViewCell 的点击
Posted
技术标签:
【中文标题】UICollectionView 的 UICollectionReusableView 防止/阻止对 UICollectionViewCell 的点击【英文标题】:UICollectionView's UICollectionReusableView preventing / blocking taps on UICollectionViewCell 【发布时间】:2017-05-16 16:12:20 【问题描述】:我正在使用带有流布局的 UICollectionView。我已经设置了标题,这是一个 UICollectionReusableView 的行为;
layout?.sectionHeadersPinToVisibleBounds = true
...
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView
let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "header", for: indexPath as IndexPath)
header.layer.zPosition = -1
return header
这会产生预期的效果,即当向上滚动单元格时,标题保持固定但位于常规单元格的后面。
但是,如果我尝试单击向顶部滚动的 UICollectionViewCell,即它在技术上覆盖了 UICollectionReusableView,则 UICollectionViewCell 的 didSelectItemAt 轻击事件将不再触发,直到我将其从标题所在的位置向下滚动。换句话说,UICollectionReusableView 会阻止点击手势,即使它的 zPosition 设置为 -1 并且不可见。
有没有人遇到过这个问题,你是如何解决的?
【问题讨论】:
我没有尝试过,但听起来header.layer.zPosition = -1
只是将layer
推回去,而不是标题 view 本身(相当惊讶它完全有效,真的)。
标题“视图”仍然存在,因为您已将其固定。正如 DonMag 提到的,从视觉上看,您只是将其图层移回。似乎您根本不想要 header 而是其他类型的对象,您可以在布局中创建它。
我发现一个解决方法是设置header.isUserInteractionEnabled = false
- 但是如果标题包含一个 UIButton(我的)那么这将破坏按钮。我认为我的解决方案是将它们全部丢弃(停止固定标题)或在滚动时切换header.isUserInteractionEnabled = false
。
【参考方案1】:
将此添加到您的部分标题视图类:
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool
return false
会将所有触摸传递给下面的下一个接收器 - 在这种情况下,您的集合视图单元格。如果您需要 Section Header 中的交互元素(例如按钮),您可以这样做:
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool
let ptInSub = theButton.convert(point, from: theButton.superview)
if theButton.bounds.contains(ptInSub)
return true
return false
这个可以给你你想要的,虽然......如果单元格视图覆盖了节标题上的按钮,并且你点击按钮所在的单元格,按钮将占据轻敲。应该可以通过另一个 contains(point)
或两个来解决这个问题......
【讨论】:
【参考方案2】:我最终在 UICollectionReusableView 标头中添加了视差效果。那里有一些 Parallax 库,但实际上非常简单 - 我使用以下代码实现了它;
override func scrollViewDidScroll(_ scrollView: UIScrollView)
if header != nil
let scrollDiff = scrollView.contentOffset.y - self.previousScrollOffset
let absoluteTop: CGFloat = 0;
let absoluteBottom: CGFloat = scrollView.contentSize.height - scrollView.frame.size.height;
let isScrollingDown = scrollDiff > 0 && scrollView.contentOffset.y > absoluteTop
let isScrollingUp = scrollDiff < 0 && scrollView.contentOffset.y < absoluteBottom
var newHeight = self.headerHeight
if isScrollingDown
newHeight = max(self.minHeaderHeight, self.headerHeight - abs(scrollDiff))
else if isScrollingUp
newHeight = min(self.maxHeaderHeight, self.headerHeight + abs(scrollDiff))
if newHeight != self.headerHeight
self.headerHeight = newHeight
self.collectionView?.contentOffset = CGPoint(x: (self.collectionView?.contentOffset.x)!, y: self.previousScrollOffset)
self.collectionView?.collectionViewLayout.invalidateLayout()
self.previousScrollOffset = scrollView.contentOffset.y
然后改变页眉的高度(在你 invalidateLayout() 时调用);
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize
return CGSize(width: collectionView.bounds.width, height:self.headerHeight)
结果是没有发生重叠,但它仍然给出了我最初想要实现的预期效果。
【讨论】:
以上是关于UICollectionView 的 UICollectionReusableView 防止/阻止对 UICollectionViewCell 的点击的主要内容,如果未能解决你的问题,请参考以下文章
Swift 中的 UiSearchController 到 UiCollectionView
UICollectionView 具有自动调整单元格(estimatedSize)和 sectionHeadersPinToVisibleBounds 的精神
根据文本调整单元格宽度 - UICollectionView - iOS