前言
随着硬件性能的不断提升,以往为了减少设备性能的消耗而进行预计算视图高度正逐步被xib约束布局替换,举个例子,我们可以直接在xib中设置好各视图控件的相对约束位置,之后根据具体的宽度来计算对应的高度,该方法能有效的降低手动计算产生误差的情况。
当然也不能完全不考虑性能问题,针对计算出来的高度需要进行缓存,减少同一视图的重复计算。
UICollectionView中的使用
布局设置
设置子视图与Collection View Cell
容器的相对位置。
由于高度需要通过子视图来计算,所以我给子视图设置了一个固定高度 128,且设置好上下间距 8,这样根据自动布局的计算,最后得到的高度就是 128+8+8=144,但是这个高度与当前contentView
的高度 200 不符合,引起了冲突。
为了消除这个冲突但又不影响高度的计算,我们有两个方法来解决,下面我们来看看具体是如何操作的。
方案一
修改子视图底部间距优先值,默认优先值为1000,适当调低优先值,这个时候会变成一条虚线,冲突解除,并且不会影响后续的计算。
方案二
调整Collection View Cell
容器的高度与设置的高度相同,但是这个方案会导致每次布局轻微的调整就引起冲突,所以不推荐使用该方案
至此就可以实现自动布局了
注意事项
Q1: 在部分iOS版本中会出现无论怎么调用 UIView
的systemLayoutSizeFitting
方法返回的结果都是初始设置的值?
这是因为UICollectionViewCell
中的contentView
视图约束并没有设定好,这个时候我们只需要对其设置约束即可。
open func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) - > CGSize
class Cell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
contentView.translatesAutoresizingMaskIntoConstraints = false
[contentView.topAnchor.constraint(equalTo: topAnchor),
contentView.leftAnchor.constraint(equalTo: leftAnchor),
contentView.rightAnchor.constraint(equalTo: rightAnchor),
contentView.bottomAnchor.constraint(equalTo: bottomAnchor)
].forEach({ $0.isActive = true })
}
required init?(coder: NSCoder) {
super.init(coder: coder)
contentView.translatesAutoresizingMaskIntoConstraints = false
[contentView.topAnchor.constraint(equalTo: topAnchor),
contentView.leftAnchor.constraint(equalTo: leftAnchor),
contentView.rightAnchor.constraint(equalTo: rightAnchor),
contentView.bottomAnchor.constraint(equalTo: bottomAnchor)
].forEach({ $0.isActive = true })
}
}
Q2: 当快速滑动时出现布局抖动的问题?
由于初始情况并不明确到底cell
有多大,这时候当实际计算结果偏差过大时就会出现这种抖动情况,我们可以给UICollectionViewFlowLayout
添加一个预估值estimatedItemSize
以减少抖动的情况,注意如果约束布局没有确定宽或高,则会直接沿用estimatedItemSize中设置的值。
func setupCollection() {
let layout = UICollectionViewFlowLayout()
layout.estimatedItemSize = CGSize(width: 100, height: 100)
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
}