高さが異なるcollectionViewCellsの束を表示する必要があります。ビューが複雑すぎるため、予想される高さを手動で計算したくありません。自動レイアウトを適用してセルの高さを計算したい
dequeueReusableCellWithReuseIdentifier
の外でcellForItemAtIndexPath
を呼び出すと、collectionViewが壊れてクラッシュします
別の問題は、セルが独立したxibにないため、一時的なセルを手動でインスタンス化して高さの計算に使用できないことです。
これに対する解決策はありますか?
public func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
var cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellIdentifier, forIndexPath: indexPath) as UICollectionViewCell
configureCell(cell, item: items[indexPath.row])
cell.contentView.setNeedsLayout()
cell.contentView.layoutIfNeeded()
return cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
}
編集:
DequeueReusableCellWithReuseIdentifierが呼び出されるとすぐにクラッシュが発生します。そのメソッドを呼び出さずにサイズを返すと、すべてがうまく機能し、計算されたサイズなしでセルが表示されます
フローレイアウトでは負のサイズまたはゼロサイズはサポートされていません
2015-01-26 18:24:34.231 [13383:9752256] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
*** First throw call stack:
(
0 CoreFoundation 0x00000001095aef35 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000109243bb7 objc_exception_throw + 45
2 CoreFoundation 0x0000000109499f33 -[__NSArrayM objectAtIndex:] + 227
3 UIKit 0x0000000107419d9c -[UICollectionViewFlowLayout _getSizingInfos] + 842
4 UIKit 0x000000010741aca9 -[UICollectionViewFlowLayout _fetchItemsInfoForRect:] + 526
5 UIKit 0x000000010741651f -[UICollectionViewFlowLayout prepareLayout] + 257
6 UIKit 0x000000010742da10 -[UICollectionViewData _prepareToLoadData] + 67
7 UIKit 0x00000001074301c6 -[UICollectionViewData layoutAttributesForItemAtIndexPath:] + 44
8 UIKit 0x00000001073fddb1 -[UICollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:viewCategory:] + 248
9 0x00000001042b824c _TFC1228BasePaginatingViewController14collectionViewfS0_FTCSo16UICollectionView6layoutCSo22UICollectionViewLayout22sizeForItemAtIndexPathCSo11NSIndexPath_VSC6CGSize + 700
10 0x00000001042b83d4 _TToFC1228BasePaginatingViewController14collectionViewfS0_FTCSo16UICollectionView6layoutCSo22UICollectionViewLayout22sizeForItemAtIndexPathCSo11NSIndexPath_VSC6CGSize + 100
11 UIKit 0x0000000107419e2e -[UICollectionViewFlowLayout _getSizingInfos] + 988
12 UIKit 0x000000010741aca9 -[UICollectionViewFlowLayout _fetchItemsInfoForRect:] + 526
13 UIKit 0x000000010741651f -[UICollectionViewFlowLayout prepareLayout] + 257
14 UIKit 0x000000010742da10 -[UICollectionViewData _prepareToLoadData] + 67
15 UIKit 0x000000010742e0e9 -[UICollectionViewData validateLayoutInRect:] + 54
16 UIKit 0x00000001073f67b8 -[UICollectionView layoutSubviews] + 170
17 UIKit 0x0000000106e3c973 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 521
18 QuartzCore 0x0000000106b0fde8 -[CALayer layoutSublayers] + 150
19 QuartzCore 0x0000000106b04a0e _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
20 QuartzCore 0x0000000106b0487e _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24
21 QuartzCore 0x0000000106a7263e _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 242
22 QuartzCore 0x0000000106a7374a _ZN2CA11Transaction6commitEv + 390
23 QuartzCore 0x0000000106a73db5 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 89
24 CoreFoundation 0x00000001094e3dc7 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
25 CoreFoundation 0x00000001094e3d20 __CFRunLoopDoObservers + 368
26 CoreFoundation 0x00000001094d9b53 __CFRunLoopRun + 1123
27 CoreFoundation 0x00000001094d9486 CFRunLoopRunSpecific + 470
28 GraphicsServices 0x000000010be869f0 GSEventRunModal + 161
29 UIKit 0x0000000106dc3420 UIApplicationMain + 1282
30 0x000000010435c709 main + 169
31 libdyld.dylib 0x000000010a0f2145 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
私はUICollectionViewでこの問題に遭遇しましたが、上記の答えに似ていますが、純粋なUICollectionViewの方法でそれを解決した方法です。
動的にするために入力するものをすべて含むカスタムUICollectionViewCellを作成します。最も簡単なアプローチのように思えるので、私はそれのために独自の.xibを作成しました。
セルを上から下に計算できるようにする制約を.xibに追加します。すべての高さを考慮していない場合、サイズ変更は機能しません。上部にビューがあり、その下にラベルがあり、その下に別のラベルがあるとします。セルの上部の制約をそのビューの上部に接続し、ビューの下部を最初のラベルの上部に、最初のラベルの下部を2番目のラベルの上部に、2番目のラベルの下部に接続する必要があります。セルの下部に。
.xibをViewControllerにロードし、viewDidLoad
のcollectionViewに登録します
let nib = UINib(nibName: CustomCellName, bundle: nil)
self.collectionView!.registerNib(nib, forCellWithReuseIdentifier: "customCellID")`
そのxibの2番目のコピーをクラスにロードし、それをプロパティとして保存して、それを使用してそのセルのサイズを決定できるようにします
let sizingNibNew = NSBundle.mainBundle().loadNibNamed(CustomCellName, owner: CustomCellName.self, options: nil) as NSArray
self.sizingNibNew = (sizingNibNew.objectAtIndex(0) as? CustomViewCell)!
View ControllerにUICollectionViewFlowLayoutDelegate
を実装します。重要なメソッドはsizeForItemAtIndexPath
と呼ばれます。そのメソッド内では、indexPathからそのセルに関連付けられているデータソースからデータをプルする必要があります。次に、sizingCellを構成し、preferredLayoutSizeFittingSize
を呼び出します。このメソッドは、self.sizingCell.preferredLayoutSizeFittingSize(targetSize)
から返されるコンテンツのインセットと高さを差し引いた幅で構成されるCGSizeを返します。
override func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
guard let data = datasourceArray?[indexPath.item] else {
return CGSizeZero
}
let sectionInset = self.collectionView?.collectionViewLayout.sectionInset
let widthToSubtract = sectionInset!.left + sectionInset!.right
let requiredWidth = collectionView.bounds.size.width
let targetSize = CGSize(width: requiredWidth, height: 0)
sizingNibNew.configureCell(data as! CustomCellData, delegate: self)
let adequateSize = self.sizingNibNew.preferredLayoutSizeFittingSize(targetSize)
return CGSize(width: (self.collectionView?.bounds.width)! - widthToSubtract, height: adequateSize.height)
}
カスタムセル自体のクラスでは、awakeFromNib
をオーバーライドし、contentView
にサイズを柔軟にする必要があることを伝える必要があります。
override func awakeFromNib() {
super.awakeFromNib()
self.contentView.autoresizingMask = [UIViewAutoresizing.FlexibleHeight]
}
カスタムセルのオーバーライドlayoutSubviews
override func layoutSubviews() {
self.layoutIfNeeded()
}
カスタムセルのクラスにpreferredLayoutSizeFittingSize
を実装します。これは、レイアウトされているアイテムに対してトリックを行う必要がある場所です。ラベルの場合、preferredMaxWidthを指定する必要があります。
func preferredLayoutSizeFittingSize(_ targetSize: CGSize)-> CGSize {
let originalFrame = self.frame
let originalPreferredMaxLayoutWidth = self.label.preferredMaxLayoutWidth
var frame = self.frame
frame.size = targetSize
self.frame = frame
self.setNeedsLayout()
self.layoutIfNeeded()
self.label.preferredMaxLayoutWidth = self.questionLabel.bounds.size.width
// calling this tells the cell to figure out a size for it based on the current items set
let computedSize = self.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
let newSize = CGSize(width:targetSize.width, height:computedSize.height)
self.frame = originalFrame
self.questionLabel.preferredMaxLayoutWidth = originalPreferredMaxLayoutWidth
return newSize
}
これらすべての手順で、正しいサイズが得られます。 0またはその他のファンキーな数字を取得する場合、制約を適切に設定していません。
Xibなしでコレクションビューセルの動的な高さを維持できます(ストーリーボードのみを使用)。
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
NSAttributedString* labelString = [[NSAttributedString alloc] initWithString:@"Your long string goes here" attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:17.0]}];
CGRect cellRect = [labelString boundingRectWithSize:CGSizeMake(cellWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin context:nil];
return CGSizeMake(cellWidth, cellRect.size.height);
}
IBのnumberOfLinesが0であることを確認してください。
TL; DR:画像にスキャンダウンし、チェックアウト ここでプロジェクトを実行しています
私が見つけたよりシンプルなソリューションのために私の答えを更新します。
私の場合、幅を固定し、セルの高さを可変にしたかったのです。回転を処理し、多くの介入を必要としない、再利用可能なドロップインソリューションが必要でした。
私がたどり着いたのは、コレクションセル(この場合は基本クラス)の(ちょうど)systemLayoutFitting(...)
をオーバーライドし、最初に制約を追加してcontentView
に間違ったディメンションを設定するUICollectionViewの努力を無効にすることでした既知の寸法、この場合は幅。
class EstimatedWidthCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
contentView.translatesAutoresizingMaskIntoConstraints = false
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
contentView.translatesAutoresizingMaskIntoConstraints = false
}
override func systemLayoutSizeFitting(
_ targetSize: CGSize, withHorizontalFittingPriority
horizontalFittingPriority: UILayoutPriority,
verticalFittingPriority: UILayoutPriority) -> CGSize {
width.constant = targetSize.width
そして、セルの最終サイズを返します-セル自体の次元に使用されますが(これはバグのように感じます)、contentView
ではありません-それ以外の場合は競合するサイズに制限されます(したがって、上記の制約)。正しいセルサイズを計算するために、フロートするディメンションの優先順位を低くし、修正する幅内にコンテンツを収めるために必要な高さを取得します。
let size = contentView.systemLayoutSizeFitting(
CGSize(width: targetSize.width, height: 1),
withHorizontalFittingPriority: .required,
verticalFittingPriority: verticalFittingPriority)
print("\(#function) \(#line) \(targetSize) -> \(size)")
return size
}
lazy var width: NSLayoutConstraint = {
return contentView.widthAnchor
.constraint(equalToConstant: bounds.size.width)
.isActive(true)
}()
}
しかし、この幅はどこから来たのでしょうか?コレクションビューのフローレイアウトのestimatedItemSize
を介して構成されます。
lazy var collectionView: UICollectionView = {
let view = UICollectionView(frame: CGRect(), collectionViewLayout: layout)
view.backgroundColor = .cyan
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
lazy var layout: UICollectionViewFlowLayout = {
let layout = UICollectionViewFlowLayout()
let width = view.bounds.size.width // should adjust for inset
layout.estimatedItemSize = CGSize(width: width, height: 10)
layout.scrollDirection = .vertical
return layout
}()
最後に、回転を処理するために、trailCollectionDidChange
を実装してレイアウトを無効にします。
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
layout.estimatedItemSize = CGSize(width: view.bounds.size.width, height: 10)
layout.invalidateLayout()
super.traitCollectionDidChange(previousTraitCollection)
}
最終結果は次のようになります。
そして、私は ここに実際のサンプル を公開しました
Swift 4。*
UICollectionViewCellのXibを作成しましたが、これは適切なアプローチのようです。
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return size(indexPath: indexPath)
}
private func size(for indexPath: IndexPath) -> CGSize {
// load cell from Xib
let cell = Bundle.main.loadNibNamed("ACollectionViewCell", owner: self, options: nil)?.first as! ACollectionViewCell
// configure cell with data in it
let data = self.data[indexPath.item]
cell.configure(withData: data)
cell.setNeedsLayout()
cell.layoutIfNeeded()
// width that you want
let width = collectionView.frame.width
let height: CGFloat = 0
let targetSize = CGSize(width: width, height: height)
// get size with width that you want and automatic height
let size = cell.contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: .defaultHigh, verticalFittingPriority: .fittingSizeLevel)
// if you want height and width both to be dynamic use below
// let size = cell.contentView.systemLayoutSizeFitting(UILayoutFittingCompressedSize)
return size
}
}
#note:このサイズを決定するケースでデータを構成するときに画像を設定することはお勧めしません。歪んだ/望ましくない結果になりました。テキストを設定しても、以下の結果しか得られませんでした。
それは非常に人気のある質問のようですので、私は謙虚な貢献をしようとします。
以下のコードはSwift 4ストーリーボードなしのセットアップのソリューションです。以前の回答からのいくつかのアプローチを利用するため、デバイスの回転に起因する自動レイアウト警告を防ぎます。
コードサンプルが少し長い場合は申し訳ありません。 StackOverflowによって完全にホストされる「使いやすい」ソリューションを提供したいと思います。投稿に対する提案がある場合は、アイデアを共有してください。それに応じて更新します。
2つのクラス:ViewController.Swift
およびMultilineLabelCell.Swift
-単一のUILabel
を含むセル。
MultilineLabelCell.Swift
import UIKit
class MultilineLabelCell: UICollectionViewCell {
static let reuseId = "MultilineLabelCellReuseId"
private let label: UILabel = UILabel(frame: .zero)
override init(frame: CGRect) {
super.init(frame: frame)
layer.borderColor = UIColor.red.cgColor
layer.borderWidth = 1.0
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
let labelInset = UIEdgeInsets(top: 10, left: 10, bottom: -10, right: -10)
contentView.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor, constant: labelInset.top).isActive = true
label.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor, constant: labelInset.left).isActive = true
label.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor, constant: labelInset.right).isActive = true
label.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor, constant: labelInset.bottom).isActive = true
label.layer.borderColor = UIColor.black.cgColor
label.layer.borderWidth = 1.0
}
required init?(coder aDecoder: NSCoder) {
fatalError("Storyboards are quicker, easier, more seductive. Not stronger then Code.")
}
func configure(text: String?) {
label.text = text
}
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
label.preferredMaxLayoutWidth = layoutAttributes.size.width - contentView.layoutMargins.left - contentView.layoutMargins.left
layoutAttributes.bounds.size.height = systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
return layoutAttributes
}
}
ViewController.Swift
import UIKit
let samuelQuotes = [
"Samuel says",
"Add different length strings here for better testing"
]
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
private(set) var collectionView: UICollectionView
// Initializers
init() {
// Create new `UICollectionView` and set `UICollectionViewFlowLayout` as its layout
collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
// Create new `UICollectionView` and set `UICollectionViewFlowLayout` as its layout
collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
title = "Dynamic size sample"
// Register Cells
collectionView.register(MultilineLabelCell.self, forCellWithReuseIdentifier: MultilineLabelCell.reuseId)
// Add `coolectionView` to display hierarchy and setup its appearance
view.addSubview(collectionView)
collectionView.backgroundColor = .white
collectionView.contentInsetAdjustmentBehavior = .always
collectionView.contentInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
// Setup Autolayout constraints
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
collectionView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
collectionView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
collectionView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
// Setup `dataSource` and `delegate`
collectionView.dataSource = self
collectionView.delegate = self
(collectionView.collectionViewLayout as! UICollectionViewFlowLayout).estimatedItemSize = UICollectionViewFlowLayout.automaticSize
(collectionView.collectionViewLayout as! UICollectionViewFlowLayout).sectionInsetReference = .fromLayoutMargins
}
// MARK: - UICollectionViewDataSource -
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MultilineLabelCell.reuseId, for: indexPath) as! MultilineLabelCell
cell.configure(text: samuelQuotes[indexPath.row])
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return samuelQuotes.count
}
// MARK: - UICollectionViewDelegateFlowLayout -
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let sectionInset = (collectionViewLayout as! UICollectionViewFlowLayout).sectionInset
let referenceHeight: CGFloat = 100 // Approximate height of your cell
let referenceWidth = collectionView.safeAreaLayoutGuide.layoutFrame.width
- sectionInset.left
- sectionInset.right
- collectionView.contentInset.left
- collectionView.contentInset.right
return CGSize(width: referenceWidth, height: referenceHeight)
}
}
このサンプルを実行するには、新しいXcodeプロジェクトを作成し、対応するファイルを作成して、AppDelegate
の内容を次のコードに置き換えます。
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var navigationController: UINavigationController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
if let window = window {
let vc = ViewController()
navigationController = UINavigationController(rootViewController: vc)
window.rootViewController = navigationController
window.makeKeyAndVisible()
}
return true
}
}
このSOに記載されている手順に従いましたが、コレクションビューのデータ(テキスト)の幅が十分に広い場合を除いて、すべて問題ありません。 systemLyaoutSizeFittingSize
のドキュメントを確認すると、この解決策があるので、要求したとおりにセルが幅を占有します。
- (CGSize)calculateSizeForSizingCell:(UICollectionViewCell *)sizingCell width:(CGFloat)width {
CGRect frame = sizingCell.frame;
frame.size.width = width;
sizingCell.frame = frame;
[sizingCell setNeedsLayout];
[sizingCell layoutIfNeeded];
CGSize size = [sizingCell systemLayoutSizeFittingSize:UILayoutFittingCompressedSize
withHorizontalFittingPriority:UILayoutPriorityRequired
verticalFittingPriority:UILayoutPriorityFittingSizeLevel];
return size;
}
これが誰かを助けることを願っています。
- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize NS_AVAILABLE_IOS(6_0);
Appleドキュメント:
-systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:を両方の優先度のUILayoutPriorityFittingSizeLevelで送信することと同等です。
Appleのドキュメントによると、デフォルト値は「かなり低い」ですが、
-[UIView systemLayoutSizeFittingSize:]を送信すると、ターゲットサイズ(引数)に最も近いサイズが計算されます。 UILayoutPriorityFittingSizeLevelは、ビューがその計算のターゲットサイズに準拠する優先レベルです。かなり低いです。通常、この優先度で制約を作成することは適切ではありません。高くしたい、または低くしたい。
したがって、デフォルトの動作を変更すると、UILayoutPriorityRequired
で幅(水平方向のフィッティング)が強制されます。
Bolnad answer をステップ4まで実行します。
次に、他のすべての手順を次のように置き換えて、より簡単にします。
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// Configure your cell
sizingNibNew.configureCell(data as! CustomCellData, delegate: self)
// We use the full width minus insets
let width = collectionView.frame.size.width - collectionView.sectionInset.left - collectionView.sectionInset.right
// Constrain our cell to this width
let height = sizingNibNew.systemLayoutSizeFitting(CGSize(width: width, height: .infinity), withHorizontalFittingPriority: UILayoutPriorityRequired, verticalFittingPriority: UILayoutPriorityFittingSizeLevel).height
return CGSize(width: width, height: height)
}
それは私のために働いた、あなたも願っています。
*注意:Nibで自動レイアウトを使用しましたが、contentViewのサブビューに上下の制約を追加することを忘れないでください
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let cell = YourCollectionViewCell.instantiateFromNib()
cell.frame.size.width = collectionView.frame.width
cell.data = viewModel.data[indexPath.item]
let resizing = cell.systemLayoutSizeFitting(UILayoutFittingCompressedSize, withHorizontalFittingPriority: UILayoutPriority.required, verticalFittingPriority: UILayoutPriority.fittingSizeLevel)
return resizing
}
@ mbm29414からの有益な回答に基づくSwift 4の回答。
残念ながら、XIBファイルを使用する必要があります。代替手段はないようです。
重要な部分は、サイズ変更セル(一度だけ作成)を使用し、コレクションビューを初期化するときにXIBを登録することです。
次に、sizeForItemAt
関数内で各セルのサイズを動的に変更します。
// UICollectionView Vars and Constants
let CellXIBName = YouViewCell.XIBName
let CellReuseID = YouViewCell.ReuseID
var sizingCell = YouViewCell()
fileprivate func initCollectionView() {
// Connect to view controller
collectionView.dataSource = self
collectionView.delegate = self
// Register XIB
collectionView.register(UINib(nibName: CellXIBName, bundle: nil), forCellWithReuseIdentifier: CellReuseID)
// Create sizing cell for dynamically sizing cells
sizingCell = Bundle.main.loadNibNamed(CellXIBName, owner: self, options: nil)?.first as! YourViewCell
// Set scroll direction
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
collectionView.collectionViewLayout = layout
// Set properties
collectionView.alwaysBounceVertical = true
collectionView.alwaysBounceHorizontal = false
// Set top/bottom padding
collectionView.contentInset = UIEdgeInsets(top: collectionViewTopPadding, left: collectionViewSidePadding, bottom: collectionViewBottomPadding, right: collectionViewSidePadding)
// Hide scrollers
collectionView.showsVerticalScrollIndicator = false
collectionView.showsHorizontalScrollIndicator = false
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// Get cell data and render post
let data = YourData[indexPath.row]
sizingCell.renderCell(data: data)
// Get cell size
sizingCell.setNeedsLayout()
sizingCell.layoutIfNeeded()
let cellSize = sizingCell.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
// Return cell size
return cellSize
}