我一直在尝试创建一个UICollectionView标头,该标头会粘贴在我的收藏夹视图的顶部。我正在使用UICollectionViewCompositionalLayout。
我尝试了多种方法:使用单元格,使用节标题并尝试弄乱插入和偏移量以使其相对于我的内容正确定位……甚至在集合视图的顶部添加一个可以监听的视图集合视图的滚动视图的contentOffset可以将自身定位在正确的位置。但是这些方法都不令人满意。他们都觉得自己像黑客一样。
我一直在做一些研究,显然您必须订阅UICollectionViewLayout,它很繁琐,仅拥有一个标题似乎有些过头,但对于整个收藏夹视图来说却是全局的。
答案 0 :(得分:2)
UICollectionViewCompositionalLayout
具有configuration
属性,您可以通过创建UICollectionViewCompositionalLayoutConfiguration
对象来设置。该对象具有一些非常好的实用功能,例如boundarySupplementaryItems
属性。
从文档中
与整个布局的边界边缘相关联的补充项目的数组,例如全局页眉和页脚。
宾果。设置此属性并在数据源中进行必要的接线,您应该具有全局头。
在这里,我要在布局中声明一个全局标头。标头是视觉效果视图中的分段控件,但您可以是UICollectionReusableView
的任何子类。
enum SectionLayoutKind: Int, CaseIterable {
case description
}
private var collectionView: UICollectionView! = nil
override func viewDidLoad() {
super.viewDidLoad()
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())
}
static func descriptionSection() -> NSCollectionLayoutSection {
// Instantiate and return a `NSCollectionLayoutSection` object.
}
func createLayout() -> UICollectionViewLayout {
let layout = UICollectionViewCompositionalLayout {
(sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
// Create your section
// add supplementaries such as header and footers that are relative to the section…
guard let layoutKind = SectionLayoutKind(rawValue: sectionIndex) else { return nil }
let section: NSCollectionLayoutSection
switch layoutKind {
case .description:
section = Self.descriptionSection()
}
return section
}
/*
✨ Magic starts HERE:
*/
let globalHeaderSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(44))
Constants.HeaderKind.globalSegmentedControl, alignment: .top)
// Set true or false depending on the desired behavior
globalHeader.pinToVisibleBounds = true
let config = UICollectionViewCompositionalLayoutConfiguration()
/*
If you want to do spacing between sections.
That's another big thing this config object does.
If you try to define section spacing at the section level with insets,
the spacing is between the items and the standard headers.
*/
config.interSectionSpacing = 20
config.boundarySupplementaryItems = [globalHeader]
layout.configuration = config
/*
End of magic. ✨
*/
return layout
}
struct Constants {
struct HeaderKind {
static let globalSegmentedControl = "segmentedControlHeader"
}
}
数据源部分的补充代码:
let globalHeaderRegistration = UICollectionView.SupplementaryRegistration<SegmentedControlReusableView>(elementKind: Constants.HeaderKind.globalSegmentedControl) { (header, elementKind, indexPath) in
// Opportunity to further configure the header
header.segmentedControl.addTarget(self, action: #selector(self.onSegmentedControlValueChanged(_:)), for: .valueChanged)
}
dataSource.supplementaryViewProvider = { (view, kind, indexPath) in
if kind == Constants.HeaderKind.globalSegmentedControl {
return self.collectionView.dequeueConfiguredReusableSupplementary(using: globalHeaderRegistration, for: indexPath)
} else {
// return another registration object
}
}