使用 UICollectionViewCompositionalLayout 时如何修改特定组的项目形状

How to modify item shape of specific group when using UICollectionViewCompositionalLayout

我正在制作一个拼贴应用,我将使用多个网格 layouts.I 我正在使用 UICollectionViewCompositionalLayout 创建网格。我的一个网格需要中间有一个心形单元格。以下是我的代码 HeartShaped 项目需要是 heartShape 我一开始不知道该怎么做我想到了使用 UIBeizerPath 但项目不是图层类型如果我设法在 cellForItem 中完成它我仍然有更多网格来了,我将不得不一次又一次地使用“if”“else”。我面临最后一组的另一个问题,即底部组未显示。

如有任何帮助,我们将不胜感激。

                let topItem = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/3), heightDimension: .fractionalHeight(1)))
                
//                top items group
                let topGroup = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1/4)), subitem: topItem, count: 3)
                topGroup.contentInsets = .init(top: 0, leading: 3, bottom: 0, trailing: 3)
                topGroup.interItemSpacing = .fixed(2)

//                middle right item
                let middleRightItem = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/4), heightDimension: .fractionalHeight(1)))

//                 middle left item
                let middleLeftItem = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/4), heightDimension: .fractionalHeight(1)))

//                Heart Shaped
                let heartShapedItem = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/2), heightDimension: .fractionalHeight(1)))

//                 middle three items group
                let middleGroup = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1/3)), subitems: [middleRightItem,heartShapedItem,middleLeftItem])
                middleGroup.contentInsets = .init(top: 0, leading: 3, bottom: 0, trailing: 3)
                middleGroup.interItemSpacing = .fixed(2)

//            bottom three items group
                let bottomGroup = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1/4)), subitem: topItem, count: 3)
                
                let finalGroup = NSCollectionLayoutGroup.vertical(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1)), subitems: [topGroup,middleGroup,bottomGroup])
                finalGroup.interItemSpacing = .fixed(2)
                
                let section = NSCollectionLayoutSection(group: finalGroup)
                
                return section

A collection view layout defines the visual arrangement of the content in your collection - 因此在您的 UICollectionViewCompositionalLayout 中,您指定 collection 视图的此类参数,例如一行中的项目数、大小和偏移量、正交滚动行为,headers 和装饰品,而不是特定单元格的外观。

cellForItem 中,您可以自定义单元格,包括其图层 - 您可以在那里修改形状。单元格将根据 UICollectionViewCompositionalLayout.

的参数排列在 collection 视图中

如果您使用 UICollectionViewDiffableDataSource,您可以使用以下代码示例区分不同类型的单元格(即具有心形和圆形的单元格):

func configureDataSource() {
    dataSource = DataSource(collectionView: collectionView) { [self] (collectionView: UICollectionView, indexPath: IndexPath, item: ViewCell) -> UICollectionViewCell? in
        switch item.type {
        case .heart:  return hearCell(for: indexPath)
        case .circle: return circleCell(for: indexPath)
        default:      return normalCell(for: indexPath)
        }
    }
}

在自定义结构 ViewCell 中,我有一个 CellType 枚举:

struct ViewCell: Hashable {
    var tag: Int
    var type: CellType
}

enum CellType { case heart, circle }

关于底部组的问题 - 您的 collection 视图中是否有足够的项目来填充所有组?

更新:

您的布局问题出在这一行:

middleGroup.interItemSpacing = .fixed(2)

有了它,中间组的3行不能放在一行。您可以删除它并通过向中间项添加插图来实现相同的间距:

heartShapedItem.contentInsets = .init(top: 0, leading: 2, bottom: 0, trailing: 2)

由于您没有使用 UICollectionViewDiffableDataSource,您可以通过 indexPath 区分您的单元格。所以如果你只有 1 个部分,你的 heartShape 项目将有 indexPath.row of 4:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCollectionViewCell.reuseID, for: indexPath) as? MyCollectionViewCell else { return UICollectionViewCell() }

    cell.label.text = "\(indexPath.row)"
    cell.label.textAlignment = .center
    cell.backgroundColor = .green
    
    if indexPath == IndexPath(row: 4, section: 0) {
        cell.label.text = "HEART"
    }
    
    return cell
}

(在你的原始代码中,底部组中的项目之间没有间距,我不知道是否有意这样做)