集合视图网格布局高度撑开

本文最后更新于 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 {// 单独 update 集合视图的高度约束
$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)
}

这样的话, 效果就更好了:


集合视图网格布局高度撑开
https://blog.rayy.top/2018/09/22/2019-5-UpdateCollectionHeightAndAnim/
作者
貘鸣
发布于
2018年9月22日
许可协议