You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在UICollectionViewCompositionalLayout中创建装饰视图并解决注册错误

问题:UICollectionViewCompositionalLayout装饰视图注册失败报错

我尝试在UICollectionViewCompositionalLayout中添加装饰视图,编写了以下代码:

创建布局Section的代码

func createListTableSection(using section: Section) -> NSCollectionLayoutSection {
    
    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/3), heightDimension: .fractionalHeight(1))
    let layoutItem = NSCollectionLayoutItem(layoutSize: itemSize)
    layoutItem.contentInsets = NSDirectionalEdgeInsets(top: 8, leading: 8, bottom: 8, trailing: 8)
        
    let layoutGroupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.93), heightDimension: .fractionalWidth(0.5))
        
    let layoutGroup = NSCollectionLayoutGroup.horizontal(layoutSize: layoutGroupSize, subitems: [layoutItem])

    let layoutSection = NSCollectionLayoutSection(group: layoutGroup)
        
    layoutSection.orthogonalScrollingBehavior = .groupPagingCentered
        
    layoutSection.decorationItems = [NSCollectionLayoutDecorationItem.background(elementKind: RoundedBackgroundView.reuseIdentifier)]
    let layout = UICollectionViewCompositionalLayout(section: layoutSection)
    layout.register(RoundedBackgroundView.self, forDecorationViewOfKind: RoundedBackgroundView.reuseIdentifier)

    return layoutSection
}

RoundedBackgroundView实现代码

class RoundedBackgroundView: UICollectionReusableView {
    static let reuseIdentifier = "RoundedBackgroundView"

    private var insetView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = .secondarySystemFill
        view.layer.cornerRadius = 15
        view.clipsToBounds = true
        return view
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .clear
        addSubview(insetView)

        NSLayoutConstraint.activate([
            insetView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 15),
            trailingAnchor.constraint(equalTo: insetView.trailingAnchor, constant: 15),
            insetView.topAnchor.constraint(equalTo: topAnchor),
            insetView.bottomAnchor.constraint(equalTo: bottomAnchor)
        ])
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

运行时触发错误:

线程1:"无法出列类型为RoundedBackgroundView的装饰视图——必须注册为类、nib或在故事板中连接原型"


解决方案

错误原因

你在createListTableSection函数里临时创建了一个UICollectionViewCompositionalLayout实例并注册了装饰视图,但这个实例并没有被实际使用——函数返回的是layoutSection,最终CollectionView使用的是其他地方创建的Layout实例,导致注册的装饰视图不生效。

修复步骤

  1. 拆分函数职责:让createListTableSection只负责创建返回NSCollectionLayoutSection,移除内部创建Layout和注册视图的代码。
  2. 在正确的位置注册:在创建最终赋值给CollectionView的Layout实例时,注册装饰视图。

修改后的代码

调整后的createListTableSection函数

func createListTableSection(using section: Section) -> NSCollectionLayoutSection {
    
    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/3), heightDimension: .fractionalHeight(1))
    let layoutItem = NSCollectionLayoutItem(layoutSize: itemSize)
    layoutItem.contentInsets = NSDirectionalEdgeInsets(top: 8, leading: 8, bottom: 8, trailing: 8)
        
    let layoutGroupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.93), heightDimension: .fractionalWidth(0.5))
        
    let layoutGroup = NSCollectionLayoutGroup.horizontal(layoutSize: layoutGroupSize, subitems: [layoutItem])

    let layoutSection = NSCollectionLayoutSection(group: layoutGroup)
        
    layoutSection.orthogonalScrollingBehavior = .groupPagingCentered
        
    layoutSection.decorationItems = [NSCollectionLayoutDecorationItem.background(elementKind: RoundedBackgroundView.reuseIdentifier)]

    return layoutSection
}

在创建CollectionViewLayout的地方注册装饰视图

// 示例:在ViewController的viewDidLoad或配置CollectionView的代码中
let targetSection = Section(...) // 你的Section实例
let listSection = createListTableSection(using: targetSection)

// 创建真正要绑定给CollectionView的Layout实例
let compositionalLayout = UICollectionViewCompositionalLayout(section: listSection)
// 在这里注册装饰视图
compositionalLayout.register(RoundedBackgroundView.self, forDecorationViewOfKind: RoundedBackgroundView.reuseIdentifier)

// 赋值给CollectionView
collectionView.collectionViewLayout = compositionalLayout

额外注意事项

确保RoundedBackgroundView的reuseIdentifier没有与其他复用视图的标识重复,避免注册冲突。


内容的提问来源于stack exchange,提问作者user214155

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 16:15:33