尽管实现了 sizeForItemAt,但 UICollectionViewFlowLayout 单元格大小永远不会改变
Posted
技术标签:
【中文标题】尽管实现了 sizeForItemAt,但 UICollectionViewFlowLayout 单元格大小永远不会改变【英文标题】:UICollectionViewFlowLayout cell size never changes despite sizeForItemAt implemented 【发布时间】:2017-12-19 20:43:25 【问题描述】:我有一个UICollectionViewCell
,里面有一个UICollectionView
,里面有UICollectionViewFlowLayout
。我正在使单元格成为集合视图的委托和数据源。我符合UICollectionViewDelegateFlowLayout
并实现collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
(并返回正确的大小)。
但是,当我调用 layout.itemSize.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
【问题讨论】:
【参考方案1】:问题
根据Apple documents for UICollectionViewFlowLayout's itemSize
如果delegate没有实现collectionView(_:layout:sizeForItemAt:)方法,流布局使用这个属性中的值来设置每个单元格的大小。这会导致所有单元格的大小都相同。
默认大小值为 (50.0, 50.0)。
它明确表示itemSize
仅在委托未实现 collectionView(_:layout:sizeForItemAt:) 方法并且没有提及itemSize
将从collectionView(_:layout:sizeForItemAt:)
返回值时使用。 它们是 2 个不同的值。这就是为什么 itemSize
不会改变,尽管 sizeForItemAt
已实现
因此,如果layout.itemSize.height
在您使用时具有默认值 (50),则它是有意义的。
您的问题有什么解决方案?
如果collectionView
上的所有单元格大小相同,我建议为itemSize
设置一个值,并且不要实现collectionView(_:layout:sizeForItemAt:)
方法(删除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|
如果collectionView
的每个单元格大小不同,则需要使用UICollectionView's layoutAttributesForItem(at:) method。在 IndexPath 处获取 UICollectionViewLayoutAttributes 并使用 layoutAttributes.size 计算
layoutAttributes.size 是从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)
【讨论】:
【参考方案2】:我认为您的注册问题...删除它并在情节提要中设置单元格。只是一个疯狂的猜测......
您有 2 个单元格,其中一个已为 collectionView 注册?
如果你在storyboard中设置单元格,注册也可能会导致问题
collectionView.register(SomeOtherCell.self, forCellWithReuseIdentifier: SomeOtherCell.reuseIdentifier)
【讨论】:
以上是关于尽管实现了 sizeForItemAt,但 UICollectionViewFlowLayout 单元格大小永远不会改变的主要内容,如果未能解决你的问题,请参考以下文章
CollectionView SizeForItemAt 基于 Cell 类?
访问 layout.collectionViewContentSize 时 collectionView(_:layout:sizeForItemAt:) 中的异常