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

如何用Compositional Layout实现自适配Cell嵌套自适配Collection View?

嵌套UICollectionView自适应高度问题解决(基于Compositional Layout)

问题说明

需要实现一个外层列表式UICollectionView(单元格占满屏幕宽度,高度随内容自适应),每个单元格内嵌套一个横向流式布局的子UICollectionView,子CollectionView占满父单元格宽度,其高度决定父单元格的高度。当前实现中子CollectionView高度为0,导致父单元格无法适配高度。

现有代码

外层CollectionView布局代码

static func autoListLayout(rowHeight: CGFloat, padding: CGFloat) -> UICollectionViewLayout {
    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(rowHeight))
    let item = NSCollectionLayoutItem(layoutSize: itemSize)
    item.contentInsets = NSDirectionalEdgeInsets.zero
    let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1))
    let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])
    group.interItemSpacing = .fixed(padding)
    let section = NSCollectionLayoutSection(group: group)
    section.orthogonalScrollingBehavior = .none
    section.contentInsets = NSDirectionalEdgeInsets(top: padding, leading: 0, bottom: padding, trailing: 0)
    section.interGroupSpacing = padding
    let layout = UICollectionViewCompositionalLayout(section: section)
    return layout
}

子CollectionView添加约束代码

addSubview(subCollectionView)
subCollectionView.isScrollEnabled = false
subCollectionView.translatesAutoresizingMaskIntoConstraints = false
subCollectionView.setContentHuggingPriority(.required, for: .vertical)
subCollectionView.setContentCompressionResistancePriority(.required, for: .vertical)
NSLayoutConstraint.activate([
    subCollectionView.leftAnchor.constraint(equalTo: leftAnchor),
    subCollectionView.rightAnchor.constraint(equalTo: rightAnchor),
    subCollectionView.topAnchor.constraint(equalTo: topAnchor),
    subCollectionView.bottomAnchor.constraint(equalTo: bottomAnchor),
])

子CollectionView布局代码

static func subLayout(rowHeight: CGFloat, padding: CGFloat) -> UICollectionViewLayout {
    let itemSize = NSCollectionLayoutSize(widthDimension: .estimated(30), heightDimension: .estimated(rowHeight))
    let item = NSCollectionLayoutItem(layoutSize: itemSize)
    item.contentInsets = NSDirectionalEdgeInsets.zero
    let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1))
    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
    group.interItemSpacing = .fixed(padding)
    let section = NSCollectionLayoutSection(group: group)
    section.orthogonalScrollingBehavior = .none
    let layout = UICollectionViewCompositionalLayout(section: section)
    return layout
}

解决方案

问题核心是布局尺寸设置错误,导致系统无法正确计算子CollectionView和父单元格的高度。需对两处布局代码进行修改:

1. 修改外层CollectionView的Group尺寸

外层CollectionView的垂直Group不能使用.fractionalHeight(1)(该设置会让Group高度占满父容器,而非自适应内容),需改为.estimated(rowHeight),让Group高度根据Item内容动态计算:

static func autoListLayout(rowHeight: CGFloat, padding: CGFloat) -> UICollectionViewLayout {
    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(rowHeight))
    let item = NSCollectionLayoutItem(layoutSize: itemSize)
    item.contentInsets = NSDirectionalEdgeInsets.zero
    // 修改此处:将heightDimension改为.estimated(rowHeight)
    let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(rowHeight))
    let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])
    group.interItemSpacing = .fixed(padding)
    let section = NSCollectionLayoutSection(group: group)
    section.orthogonalScrollingBehavior = .none
    section.contentInsets = NSDirectionalEdgeInsets(top: padding, leading: 0, bottom: padding, trailing: 0)
    section.interGroupSpacing = padding
    let layout = UICollectionViewCompositionalLayout(section: section)
    return layout
}

2. 修改子CollectionView的Group尺寸

子CollectionView的横向Group同样不能使用.fractionalHeight(1),需改为.estimated(rowHeight),让Group高度由Item高度决定,从而让子CollectionView能正确计算自身的intrinsicContentSize:

static func subLayout(rowHeight: CGFloat, padding: CGFloat) -> UICollectionViewLayout {
    let itemSize = NSCollectionLayoutSize(widthDimension: .estimated(30), heightDimension: .estimated(rowHeight))
    let item = NSCollectionLayoutItem(layoutSize: itemSize)
    item.contentInsets = NSDirectionalEdgeInsets.zero
    // 修改此处:将heightDimension改为.estimated(rowHeight)
    let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(rowHeight))
    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
    group.interItemSpacing = .fixed(padding)
    let section = NSCollectionLayoutSection(group: group)
    section.orthogonalScrollingBehavior = .none
    let layout = UICollectionViewCompositionalLayout(section: section)
    return layout
}

额外注意事项

  • 确保子CollectionView的isScrollEnabled已设置为false(你当前代码已实现),只有禁止滚动时,UICollectionView才会根据内容计算intrinsicContentSize。
  • 子CollectionView的数据更新后,若高度未自动刷新,可调用subCollectionView.invalidateIntrinsicContentSize()或让父单元格重新布局。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 01:07:05