タイプUICollectionView
のヘッダーを持つUICollectionReusableView
があります。
そこにはラベルがあり、その長さはユーザーの入力によって異なります。
したがって、ヘッダーのラベルおよびその他の要素の高さに応じて、ヘッダーのサイズを動的に変更する必要があります。
これは私の絵コンテです:
このアプリを実行したときの結果:
これは私を半日ほど夢中にさせました。これが最終的に機能したものです。
ヘッダーのラベルが動的にサイズ設定され、1行で折り返されるように設定されていることを確認してください
ラベルの制約が有限であることを確認してください。例:ボトムラベルから再利用可能なビューまでの「より大きい」制約は機能しません。上の画像をご覧ください。
ラベルを埋め込んだビューのサブクラスにアウトレットを追加します
class CustomHeader: UICollectionReusableView {
@IBOutlet weak var contentView: UIView!
}
初期レイアウトを無効にする
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
collectionView.collectionViewLayout.invalidateLayout()
}
ヘッダーをレイアウトして適切なサイズを取得します
extension YourViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
if let headerView = collectionView.visibleSupplementaryViews(ofKind: UICollectionElementKindSectionHeader).first as? CustomHeader {
// Layout to get the right dimensions
headerView.layoutIfNeeded()
// Automagically get the right height
let height = headerView.contentView.systemLayoutSizeFitting(UILayoutFittingExpandedSize).height
// return the correct size
return CGSize(width: collectionView.frame.width, height: height)
}
// You need this because this delegate method will run at least
// once before the header is available for sizing.
// Returning zero will stop the delegate from trying to get a supplementary view
return CGSize(width: 1, height: 1)
}
}
スイフト3
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize{
return CGSize(width: self.myCollectionView.bounds.width, height: self.mylabel.bounds.height)
}
以下を実装することで達成できます。
ViewController:
class ViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
// the text that you want to add it to the headerView's label:
fileprivate let myText = "Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda."
}
extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
switch kind {
case UICollectionElementKindSectionHeader:
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind,
withReuseIdentifier: "customHeader",
for: indexPath) as! CustomCollectionReusableView
headerView.lblTitle.text = myText
headerView.backgroundColor = UIColor.lightGray
return headerView
default:
fatalError("This should never happen!!")
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 100
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "customCell", for: indexPath)
cell.backgroundColor = UIColor.brown
// ...
return cell
}
}
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
// ofSize should be the same size of the headerView's label size:
return CGSize(width: collectionView.frame.size.width, height: myText.heightWithConstrainedWidth(font: UIFont.systemFont(ofSize: 17)))
}
}
extension String {
func heightWithConstrainedWidth(font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: UIScreen.main.bounds.width, height: CGFloat.greatestFiniteMagnitude)
let boundingBox = self.boundingRect(with: constraintRect, options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
return boundingBox.height
}
}
カスタムUICollectionReusableView
:
class CustomCollectionReusableView: UICollectionReusableView {
@IBOutlet weak var lblTitle: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// setup "lblTitle":
lblTitle.numberOfLines = 0
lblTitle.lineBreakMode = .byWordWrapping
lblTitle.sizeToFit()
}
}
これがエレガントで最新のソリューションです。
他の人が述べたように、まず、ヘッダービューの最上部から最初のサブビューの最上部、最初のサブビューの最下部から2番目のサブビューの最上部など、および最後のサブビューの下部からヘッダービューの下部まで。そうして初めて、自動レイアウトはビューのサイズを変更する方法を知ることができます。
次のコードは、ヘッダービューの計算されたサイズを返します。
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
// Get the view for the first header
let indexPath = IndexPath(row: 0, section: section)
let headerView = self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionHeader, at: indexPath)
// Use this view to calculate the optimal size based on the collection view's width
return headerView.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height),
withHorizontalFittingPriority: .required, // Width is fixed
verticalFittingPriority: .fittingSizeLevel) // Height can be as large as needed
}