尽管实现了sizeForItemAt,UICollectionViewFlowLayout单元格的大小从未改变

nam*_*tee 5 ios uicollectionview uicollectionviewlayout swift

我有一个UICollectionViewCell具有UICollectionViewUICollectionViewFlowLayout内。我将单元格作为集合视图的委托和数据源。我正在遵循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
  }
}
Run Code Online (Sandbox Code Playgroud)

tru*_*duc 6

问题

  • 根据Apple文档中UICollectionViewFlowLayout的itemSize

    如果委托未实现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|
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果collectionView每个单元格的大小不同,则需要使用UICollectionView的layoutAttributesForItem(at :)方法。从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)
    
    Run Code Online (Sandbox Code Playgroud)