如何无需设置高度约束实现底部单行UICollectionView布局?
我希望在屏幕底部放置一个单行UICollectionView,其上方是一个文本输入框(红色矩形为文本框,绿色为UICollectionView)。当前已通过代码完成布局设置,并使用UICollectionViewCompositionalLayout创建了布局,其中已为group设置heightDimension: .absolute(140),但目前给UICollectionView添加了固定高度160的约束。我希望移除该高度约束,让UICollectionView自行根据布局计算高度,请问该如何实现?
当前设置代码:
view.addSubview(queryTextField) view.addSubview(suggestionsCollectionView) NSLayoutConstraint.activate([ queryTextField.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), queryTextField.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), queryTextField.bottomAnchor.constraint(equalTo: suggestionsCollectionView.topAnchor), suggestionsCollectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), suggestionsCollectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), suggestionsCollectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), suggestionsCollectionView.heightAnchor.constraint(equalToConstant: 160) ]) ... private func createCollectionViewLayout() -> UICollectionViewCompositionalLayout { return UICollectionViewCompositionalLayout { (_, _) -> NSCollectionLayoutSection? in // item let item = NSCollectionLayoutItem( layoutSize: NSCollectionLayoutSize( widthDimension: .fractionalWidth(1/3), heightDimension: .fractionalHeight(1) ) ) item.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 8) // group let group = NSCollectionLayoutGroup.horizontal( layoutSize: NSCollectionLayoutSize( widthDimension: .fractionalWidth(1), heightDimension: .absolute(140) ), repeatingSubitem: item, count: 3 ) group.contentInsets = NSDirectionalEdgeInsets(top: 16, leading: 0, bottom: 16, trailing: 0) // section let section = NSCollectionLayoutSection(group: group) section.orthogonalScrollingBehavior = .continuous section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20) // return return section } }
要实现UICollectionView根据CompositionalLayout自动计算高度,按以下步骤操作:
移除固定高度约束
直接删掉约束数组中的suggestionsCollectionView.heightAnchor.constraint(equalToConstant: 160)这一行,这是最基础的一步。自定义UICollectionView子类以支持自动计算高度
横向滚动的CompositionalLayout默认不会让系统自动推导CollectionView的垂直高度,所以需要自定义子类重写相关方法来返回正确的内容尺寸:class SelfSizingCollectionView: UICollectionView { override var intrinsicContentSize: CGSize { return collectionViewLayout.collectionViewContentSize } override func layoutSubviews() { super.layoutSubviews() // 当布局内容尺寸变化时,通知系统更新自身固有尺寸 if !bounds.size.equalTo(intrinsicContentSize) { invalidateIntrinsicContentSize() } } }然后将你的
suggestionsCollectionView替换为这个自定义类,比如:let suggestionsCollectionView = SelfSizingCollectionView(frame: .zero, collectionViewLayout: createCollectionViewLayout())设置内容优先级
让CollectionView优先使用自身内容尺寸来确定高度,添加以下代码:suggestionsCollectionView.setContentHuggingPriority(.required, for: .vertical) suggestionsCollectionView.setContentCompressionResistancePriority(.required, for: .vertical)验证布局配置
你的CompositionalLayout中group高度已设为固定140,加上group上下内边距各16,系统会自动计算出CollectionView的总高度为140 + 16 + 16 = 172,无需手动写死数值。后续如果修改group高度或内边距,CollectionView的高度也会自动同步更新。
内容的提问来源于stack exchange,提问作者smeshko

