约束UICollectionView的高度以匹配内容的高度

时间:2018-09-23 06:30:31

标签: ios swift cocoa-touch

我有一个使用UICollectionViewFlowLayout的UICollectionView。滚动方向是垂直的,但是我只有少量(可变)的单元格,不需要或不想滚动。集合视图的顶部,前导和尾随都限于父视图。我正在尝试使集合视图的高度适合其内容。

如果我使用这个,初始高度看起来是正确的:

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
    var collection: UICollectionView!
    var heightConstraint: NSLayoutConstraint!

    override func loadView() {
        super.loadView()
        self.collection = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
        self.collection.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(self.collection)
        // ...
        self.collection.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
        self.collection.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor).isActive = true
        self.collection.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor).isActive = true

        // Create placeholder constraint
        self.heightConstraint = self.collection.heightAnchor.constraint(equalToConstant: 1)
        self.heightConstraint.isActive = true
    }

    func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        // Update placeholder constraint
        self.heightConstraint.constant = self.collection.contentSize.height
    }

    // ...
}

但是,当内容布局更改(例如,设备方向更改)时,这不会更新集合视图的高度。当内容布局更改时,是否有一种方法可以更新约束常数?还是使用动态约束而不是常量的方法?

Swift 4.2,Xcode 10.0,目标iOS 12。

2 个答案:

答案 0 :(得分:2)

viewDidLayoutSubviews是更新约束的更好位置,它在每次重新布局(方向更改,大小更改等)之后都会被调用。另外,向集合视图布局询问内容大小更加可靠:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    // Update placeholder constraint
    self.heightConstraint.constant = self.collection.collectionViewLayout.collectionViewContentSize.height
}

答案 1 :(得分:0)

这是一个解决方案:

lazy var collectionView: UICollectionView = {
    let collection = UICollectionView(frame:CGRect.zero, collectionViewLayout: collectionViewFlowLayout)
    collection.translatesAutoresizingMaskIntoConstraints = false
    collection.backgroundColor = .red
    collection.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "myCollectionCell")
    return collection
}()

var defaultConstraints: [NSLayoutConstraint]?

var heightConstraint:[NSLayoutConstraint]?

let collectionViewFlowLayout: UICollectionViewFlowLayout = {
    let flow = UICollectionViewFlowLayout()
    flow.scrollDirection = .vertical
    flow.itemSize = CGSize(width: 120.0, height: 170.0)
    return flow
}()

override func updateViewConstraints() {
super.updateViewConstraints()
    if defaultConstraints == nil {
        defaultConstraints = [
            collectionView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),
            collectionView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor),
            collectionView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor),
            collectionView.bottomAnchor.constraint(equalTo: self.collectionView.safeAreaLayoutGuide.bottomAnchor)
        ]
         heightConstraint = [collectionView.heightAnchor.constraint(equalToConstant: 100)]
heightConstraint?.first!.priority = .defaultHigh
        NSLayoutConstraint.activate(defaultConstraints! + heightConstraint!)
    }

}

override func viewDidLoad() {
    super.viewDidLoad()
    view.addSubview(self.collectionView)
    collectionView.delegate = self
    collectionView.dataSource = self
    view.updateConstraintsIfNeeded()
}

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
     heightConstraint?.first?.constant = collectionView.collectionViewLayout.collectionViewContentSize.height
}


func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 3
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCollectionCell", for: indexPath)
    cell.backgroundColor = .yellow
    return cell
}

func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 1
}