Callback to sectionHeadersPinToVisibleBounds



我的项目中有一个要求,当UICollectionView标头变得粘稠时,我必须为它们添加阴影。

我正在使用UICollectionViewFlowLayout部分HeadersPinToVisibleBounds上的属性,当设置为YES时,会使标题具有粘性。

当标头变得粘稠并实际固定到顶部时,我们可以得到某种回调,以便我可以为该标头添加阴影吗?我不希望当标题不粘时阴影在那里。

这里的挑战是,我无法真正利用方法中的信息 - 布局属性补充视图:这确实为我提供了屏幕上的视图,因为我的部分具有动态的项目,因此屏幕上的哪个部分并没有真正告诉我谁需要阴影。

我设法通过以下方式找到了这个问题的解决方案:

  1. 手动将标题的位置保存在:

    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { 
    let cell = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "CategoryNameReusableView", for: indexPath) as! CategoryNameReusableView
                cell.nameLbl.text = sectionNames[indexPath.section]
                if viewWithPosition.isEmpty { viewWithPosition.append(( name: cell.nameLbl.text!, position: cell.frame.origin.y))}
                let x = isElementInArray(array: viewWithPosition, string: cell.nameLbl.text!)
                if !x {
                    viewWithPosition.append((name: cell.nameLbl.text!, position: cell.frame.origin.y))
                }
            return cell
    }
    

我正在使用一个视图与位置元组数组var viewWithPosition = [(name: String, position: CGFloat)]()。如果我只保存单元格的位置,情况可能是一样的,但由于我的单元格有不同的文本,我使用name参数来检查数组中是否已存在该元素。我使用了辅助功能:

fileprivate func isElementInArray(array: [ViewAndPosition], string: String) -> Bool {
    var bool = false
    for views in array {
        if views.name == string {
            bool = true
            return bool
        }
    }
    return bool
}
  1. 当我有初始位置时,我会检查可见的标题是否放错了位置:

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if let visibleHeadersInSection = collectionView.visibleSupplementaryViews(ofKind: UICollectionElementKindSectionHeader) as? [CategoryNameReusableView] {
        for header in visibleHeadersInSection{
            if let index = viewWithPosition.index(where: { (element) -> Bool in
                element.name == header.nameLbl.text
            }){
                if header.frame.origin.y == viewWithPosition[index].position {
                    header.backgroundColor = UIColor.clear
                } else {
                    header.backgroundColor = UIColor.white
                }
            }
        }
    }
    

    }

目前,苹果似乎没有针对这种情况提供回调。希望这也是您的解决方案。

我已经对 IvanMih 的解决方案进行了现代化和改进。请注意,UICollectionView中显示的数据集headerGroupsBeingDisplayed

// Array of tuples that stores data about all inflated headers. Used for conditionally changing sticky header color.
// The "position" is the original vertical position of the header view relative to its frame. When a header sticks to the top, the header view is no longer aligned with its frame.
// We exploit this lack of alignment to detect when a given header is stuck to the top.
var headerStringsAndOriginalPositions = [(name: String, position: CGFloat)]()

// Specify how Header views get inflated. Add a header to headerStringsAndOriginalPositions if not already present.
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
    let cell = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "DateHeaderReusableView", for: indexPath) as! DateHeaderReusableView
    let dateHeaderString = headerGroupsBeingDisplayed[indexPath.section].dateHeader
    cell.dateLabel.text = dateHeaderString
    if (!headerStringsAndOriginalPositions.contains(where: { name, position in name == dateHeaderString })) {
        headerStringsAndOriginalPositions.append((name: dateHeaderString, position: cell.frame.origin.y))
    }
    return cell
}

// Every time user scrolls, iterate through list of visible headers and check whether they're sticky or not. Then modify the header views accordingly.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if let visibleHeadersInSection = collectionView.visibleSupplementaryViews(ofKind: UICollectionView.elementKindSectionHeader) as? [DateHeaderReusableView] {
        for header in visibleHeadersInSection {
            if let index = headerStringsAndOriginalPositions.firstIndex(where: { (element) -> Bool in element.name == header.dateLabel.text }) {
                if (header.frame.origin.y == headerStringsAndOriginalPositions[index].position) {
                    // Header is non-sticky (as header view is aligned with its frame).
                    header.dateLabel.textColor = .red
                } else {
                    // Header is sticky (as header view is not aligned with its frame).
                    header.dateLabel.textColor = .blue
                }
            }
        }
    }
}

相关内容

  • 没有找到相关文章

最新更新