我正在尝试使用collectionview部分标题创建一个可伸缩的标头。有很多不同的方法可以做到这一点,但我只是在寻找最简单,最直接的方法,明确的做法是什么。有没有人在Swift 3中看过一个关于这样做的简单指南,或者你能解释一下这将如何在这里完成吗?
我认为不应该那么困难。我想使用UICollectionViewDelegateFlowLayout
和ScrollviewDelegate
因为我认为这将是最简单的方法。
我可以使用scrollViewDidScroll
方法在用户滚动时控制标题的高度。如何手动更改标题的高度?我知道在故事板上我可以在UICollectionView
标题大小设置中更改它,但我如何在代码中调整它?
答案 0 :(得分:1)
您可以覆盖UICollectionViewFlowLayout
子类中的shouldInvalidateLayout(forBoundsChange:)
和layoutAttributesForElements(in:)
方法,以便在UICollectionView
中创建弹性标题。
以下Swift 4 / iOS 11完整代码显示了如何实现这些方法。
CollectionViewController.swift
import UIKit
class CollectionViewController: UICollectionViewController {
let flowLayout = CustomFlowLayout()
override func viewDidLoad() {
super.viewDidLoad()
guard let collectionView = collectionView else { fatalError() }
collectionView.alwaysBounceVertical = true
collectionView.contentInsetAdjustmentBehavior = .always
collectionView.collectionViewLayout = flowLayout
collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
collectionView.register(HeaderReusableView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "HeaderView")
}
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "HeaderView", for: indexPath) as! HeaderReusableView
return headerView
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
return collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
}
}
CustomFlowLayout.swift
import UIKit
class CustomFlowLayout: UICollectionViewFlowLayout {
let idealCellWidth: CGFloat = 100
let margin: CGFloat = 10
override init() {
super.init()
sectionInsetReference = .fromSafeArea
sectionInset = UIEdgeInsets(top: margin, left: margin, bottom: margin, right: margin)
headerReferenceSize = CGSize(width: 0, height: 80)
sectionHeadersPinToVisibleBounds = false
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepare() {
super.prepare()
guard let collectionView = collectionView else { return }
let availableWidth = collectionView.frame.width - collectionView.safeAreaInsets.left - collectionView.safeAreaInsets.right - sectionInset.left - sectionInset.right
let idealNumberOfCells = (availableWidth + minimumInteritemSpacing) / (idealCellWidth + minimumInteritemSpacing)
let numberOfCells = idealNumberOfCells.rounded(.down)
let cellWidth = (availableWidth + minimumInteritemSpacing) / numberOfCells - minimumInteritemSpacing
itemSize = CGSize(width: cellWidth, height: cellWidth)
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let collectionView = collectionView else { return nil }
guard let rectAttributes = super.layoutAttributesForElements(in: rect) else { return nil }
let offsetY = collectionView.contentOffset.y + collectionView.safeAreaInsets.top
if let firstHeader = rectAttributes.first(where: { $0.representedElementKind == UICollectionElementKindSectionHeader && offsetY < 0}) {
let origin = CGPoint(x: firstHeader.frame.origin.x, y: firstHeader.frame.minY - offsetY.magnitude)
let size = CGSize(width: firstHeader.frame.width, height: max(0, headerReferenceSize.height + offsetY.magnitude))
firstHeader.frame = CGRect(origin: origin, size: size)
}
return rectAttributes
}
}
CollectionViewCell.swift
import UIKit
class CollectionViewCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .cyan
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
HeaderReusableView.swift
import UIKit
class HeaderReusableView: UICollectionReusableView {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .magenta
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
预期结果: