Reputation: 1568
I have a UICollectionViewCell
that has a UICollectionView
with UICollectionViewFlowLayout
inside. I am making the cell the delegate and the datasource of the collection view. I am conforming to UICollectionViewDelegateFlowLayout
and implementing collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
(and returning the correct size).
However, when I call layout.itemSize.height
I get the default height, 50.
class MyCell: UICollectionViewCell {
fileprivate lazy var collectionView: UICollectionView = {
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(SomeOtherCell.self, forCellWithReuseIdentifier: SomeOtherCell.reuseIdentifier)
collectionView.showsHorizontalScrollIndicator = false
collectionView.showsVerticalScrollIndicator = false
return collectionView
}()
fileprivate lazy var layout: UICollectionViewFlowLayout? = {
let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
layout?.scrollDirection = .horizontal
layout?.sectionInset = UIEdgeInsets.zero
return layout
}()
override func sizeThatFits(_ size: CGSize) -> CGSize {
collectionView.frame = CGRect(x: layoutMargins.left, y: origin.y, width: width, height: layout.itemSize.height)
// layout.itemSize.height is always 50
}
}
extension MyCell: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
guard tags.count != 0 else {
return .zero
}
let tag = Tag(text: tags[indexPath.item], index: indexPath.item)
placeholderCell.configure(with: tag)
let size = placeholderCell.getFrame(at: .zero, fitting: placeholderCell.width, alignedBy: semanticContentAttribute, apply: false).size
collectionViewWidth += size.width
// this size is always correct, that's what I want when I call layout.itemSize.height
return size
}
}
Upvotes: 7
Views: 3249
Reputation: 122
I think your problem with register ... remove it and set the cell in storyboard. Just a wild guess...
You have 2 cells which one is registered for the collectionView?
In case you set the cell in storyboard, register might also cause a problem
collectionView.register(SomeOtherCell.self, forCellWithReuseIdentifier: SomeOtherCell.reuseIdentifier)
Upvotes: -1
Reputation: 12144
According to Apple documents for UICollectionViewFlowLayout's itemSize
If the delegate does not implement the collectionView(_:layout:sizeForItemAt:) method, the flow layout uses the value in this property to set the size of each cell. This results in cells that all have the same size.
The default size value is (50.0, 50.0).
It says clearly that itemSize
is only used when the delegate does not implement the collectionView(_:layout:sizeForItemAt:) method and no words mention that itemSize
will return value from collectionView(_:layout:sizeForItemAt:)
. They are 2 different values. That's why itemSize
won't change despite sizeForItemAt
is implemented
So it makes sense if layout.itemSize.height
has default value (50) when you use it.
If all of cells on your collectionView
have same size, I suggest to set a value for itemSize
and don't implement collectionView(_:layout:sizeForItemAt:)
method (Remove extension for UICollectionViewDelegateFlowLayout
).
class MyCell: UICollectionViewCell {
fileprivate lazy var collectionView: UICollectionView = {
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
// collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(SomeOtherCell.self, forCellWithReuseIdentifier: SomeOtherCell.reuseIdentifier)
collectionView.showsHorizontalScrollIndicator = false
collectionView.showsVerticalScrollIndicator = false
return collectionView
}()
fileprivate lazy var layout: UICollectionViewFlowLayout? = {
let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
layout?.scrollDirection = .horizontal
layout?.sectionInset = UIEdgeInsets.zero
// Calculate and change |itemSize| here
layout?.itemSize = YOUR_CELL_SIZE_AFTER_CALCULATED
return layout
}()
override func sizeThatFits(_ size: CGSize) -> CGSize {
collectionView.frame = CGRect(x: layoutMargins.left, y: origin.y, width: width, height: layout.itemSize.height)
// layout.itemSize.height is |YOUR_CELL_SIZE_AFTER_CALCULATED.height|
}
}
If collectionView
has different size for each cell, you need to use UICollectionView's layoutAttributesForItem(at:) method. Get UICollectionViewLayoutAttributes at an IndexPath and use layoutAttributes.size to calculate
layoutAttributes.size is value returned from collectionView(_:layout:sizeForItemAt:)
let indexPath = // IndexPath you need to use to calculate
let layoutAttributes : UICollectionViewLayoutAttributes? = collectionView.layoutAttributesForItem(at: indexPath)
// Use this value to calculate |collectionView| frame
print(layoutAttributes?.size)
Upvotes: 7