【问题标题】:UICollectionView's UICollectionReusableView preventing / blocking taps on UICollectionViewCellUICollectionView 的 UICollectionReusableView 防止/阻止对 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

标签: ios swift uicollectionview


【解决方案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)
    }
    

    结果是没有发生重叠,但它仍然给出了我最初想要实现的预期效果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-12-31
      • 1970-01-01
      • 1970-01-01
      • 2011-04-04
      • 2014-05-29
      • 1970-01-01
      • 2012-06-14
      相关资源
      最近更新 更多