我的项目中有一个要求,当UICollectionView标头变得粘稠时,我必须为它们添加阴影。
我正在使用UICollectionViewFlowLayout部分HeadersPinToVisibleBounds上的属性,当设置为YES时,会使标题具有粘性。
当标头变得粘稠并实际固定到顶部时,我们可以得到某种回调,以便我可以为该标头添加阴影吗?我不希望当标题不粘时阴影在那里。
这里的挑战是,我无法真正利用方法中的信息 - 布局属性补充视图:这确实为我提供了屏幕上的视图,因为我的部分具有动态的项目,因此屏幕上的哪个部分并没有真正告诉我谁需要阴影。
我设法通过以下方式找到了这个问题的解决方案:
-
手动将标题的位置保存在:
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
}
当我有初始位置时,我会检查可见的标题是否放错了位置:
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
}
}
}
}
}