本文最后更新于 2021年4月4日 晚上
本文讨论集合视图 + UICollectionViewFlowLayout + AutoLayout 时, 集合视图高度撑开至其 contentView
高度的方法.
实现思路介绍
首先来看一个简单的代码, 如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| private func setupCollectionView() { _collectionView = UICollectionView(frame: .zero, collectionViewLayout: _flowLayout) _topView.addSubview(_collectionView) _collectionView.snp.makeConstraints { $0.edges.equalToSuperview() $0.height.equalTo(0) } }
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) _collectionView.snp.updateConstraints { $0.height.equalTo(250) } }
|
而这段代码所在的上下文是这样的:
视图控制器的视图中有一个 UIScrollView
.
在 UIScrollView
中有一个 _topView
和一个 _bottomView
.
将集合视图放入 _topView
中, 当集合视图内容布局完成后, 它将 _topView
的高度按 contentSize
中的高度撑开.
代码中显示的仅仅是一套最基本的撑开操作, 下面来看如何在布局完成的时机将界面撑开.
实际代码
上面的代码没有解决在 “什么时候” 布局完成的问题, 其实有一个很取巧的做法, 无需观察 contentSize
的改变就可以达到目的, 如下所示:
1 2 3 4 5 6 7 8
| _collectionView.performBatchUpdates({ print("内容更新: \(self._collectionView.contentSize)") }, completion: { _ in print("内容更新完成: \(self._collectionView.contentSize)") self._collectionView.snp.updateConstraints { $0.height.equalTo(self._collectionView.contentSize.height) } })
|
performBatchUpdates
用于对集合视图进行批量修改操作. 而这里没有执行任何修改内容的操作, 而是利用它提供的完成回调来查看首次布局完成后的 contentSize
.
而这段代码的添加位置是在 viewDidLoad
, 这样在完成布局后即可获取到 contentSize
的准确值了.
最终效果如下所示(为了便于演示, 故添加了动画效果):
UIFlowLayout + AutoLayout + Self-Sizing 时候的自动撑开
上面的代码仅仅针对固定的 ItemSize 的情况, 如果设置 estimatedItemSize
, 则需要额外进行处理.
当前的布局参数配置如下:
1 2 3 4 5 6
| private func configFlowLayout() { _flowLayout.minimumLineSpacing = 8.0 _flowLayout.minimumInteritemSpacing = 8.0 _flowLayout.sectionInset = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) _flowLayout.estimatedItemSize = CGSize(width: 1.0, height: 1.0) }
|
新建集合视图 Cell, 内部仅含有一个 UILabel:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class MyCollectionCell: UICollectionViewCell { private let _label = UILabel()
override init(frame: CGRect) { super.init(frame: frame)
contentView.addSubview(_label) _label.snp.makeConstraints { $0.edges.equalToSuperview() } }
func setText(_ text: String?) { _label.text = text } }
|
实践发现, 原来如果集合视图的初始高度约束设置过小(比如之前设置的 0, 或者 1, 是无法正确布局内部的), 故将集合视图的初始高度约束从:
1 2 3 4
| _collectionView.snp.makeConstraints { $0.edges.equalToSuperview() $0.height.equalTo(0) }
|
修改为:
1 2 3 4
| _collectionView.snp.makeConstraints { $0.edges.equalToSuperview() $0.height.equalTo(10) }
|
这样就可以正确地布局内部内容, 且高度仍然可以更新正常, 如下所示(为了便于演示, 还是添加了动画过程):
如果觉得上面的 Cell 中 Label 的边距离 Cell 的太近, 可以直接设置 Label 的约束为如下:
1 2 3
| _label.snp.makeConstraints { $0.edges.equalToSuperview().inset(8) }
|
这样的话, 效果就更好了: