首页 > 解决方案 > 使用动态大小 uicollectionView 单元格时如何为特定单元格设置大小

问题描述

我正在关注本教程:

https://www.raywenderlich.com/4829472-uicollectionview-custom-layout-tutorial-pinterest

实现这个布局 在此处输入图像描述

基本上是水平collectionView输入section 1和垂直collectionView输入section 2

我的想法是在第一个单元格中放置一个 collectionView,它的大小应该是:CGSize(width: screen.width, height: 100)

但由于我使用的是链接中的方法,我不知道如何为第一个单元格指定特定大小。这是我尝试过的:

在此处输入图像描述

标签: swiftuicollectionviewuicollectionviewcell

解决方案


免责声明:由于 OP 之前曾问过一个关于如何创建 Pinterest 布局的问题,并且我在评论中建议了 Raywenderlich 教程,我相信 OP 提出的这个问题是该问题的扩展

回答:

查看您添加的设计,我相信您正在尝试添加一个CollectionView具有水平滚动的作为跨越整个集合视图宽度的第一个单元格。因为你已经继承了UICollectionViewFlowLayout你需要在prepare方法本身中处理这种特殊情况

    override func prepare() {
        // 1
        guard
            cache.isEmpty,
            let collectionView = collectionView
        else {
            return
        }
        // 2
        let columnWidth = contentWidth / CGFloat(numberOfColumns)
        var xOffset: [CGFloat] = []
        for column in 0..<numberOfColumns {
            xOffset.append(CGFloat(column) * columnWidth)
        }
        var column = 0
        var yOffset: [CGFloat] = .init(repeating: 0, count: numberOfColumns)

        // 3
        for item in 0..<collectionView.numberOfItems(inSection: 0) {
            let indexPath = IndexPath(item: item, section: 0)
            let attributes: UICollectionViewLayoutAttributes
            let photoHeight = delegate?.collectionView(
                collectionView,
                heightForPhotoAtIndexPath: indexPath) ?? 180
            let height = cellPadding * 2 + photoHeight
            let frame: CGRect

            if item == 0 {
                frame = CGRect(x: 0,
                               y: yOffset[column],
                               width: columnWidth,
                               height: height)

                contentHeight = frame.maxY
                for column in 0..<numberOfColumns {
                    yOffset[column] = frame.maxY
                }
                column = 0
            }
            else {
                // 4
                frame = CGRect(x: xOffset[column],
                               y: yOffset[column],
                               width: columnWidth,
                               height: height)

                contentHeight = max(contentHeight, frame.maxY)
                yOffset[column] = yOffset[column] + height
                column = column < (numberOfColumns - 1) ? (column + 1) : 0
            }

            let insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)
            attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
            attributes.frame = insetFrame
            cache.append(attributes)
        }
    }

在您的for item in 0..<collectionView.numberOfItems(inSection: 0) {我添加了一个特殊条件来处理if item == 0 {where in 而不是使用列宽,我使用了内容宽度(根据您的设计,您希望第一个单元格覆盖集合视图的整个宽度)

最后在您的委托方法中

extension PhotoStreamViewController: PinterestLayoutDelegate {
  func collectionView(
      _ collectionView: UICollectionView,
      heightForPhotoAtIndexPath indexPath:IndexPath) -> CGFloat {
          if indexPath.row == 0 {
              return 180 // whatever is the height of first cell
          }
          return photos[indexPath.item].image.size.height
      }
}

一个警告

在您的设计中,我可以看到您添加了两个部分标题Header 1Header 2我猜在这种情况下您返回的部分数量至少为 2,但是如果您注意到,本教程侧重于单个部分集合视图

for item in 0..<collectionView.numberOfItems(inSection: 0) {

第 0 部分是硬编码的,如果您想处理多个部分并且可能需要大量修改,则可能必须动态处理它prepare


推荐阅读