限制 UICollectionView 高度以匹配内容的高度
Constrain UICollectionView height to match height of contents
我有一个使用 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
}
// ...
}
但是当内容布局发生变化时(例如设备方向发生变化),这不会更新集合视图的高度。有没有办法在内容布局发生变化时更新约束常量?或者使用动态约束而不是常量的方法?
Swift4.2,Xcode10.0,目标iOS12.
更新约束的更好位置是 viewDidLayoutSubviews
,它会在每次重新布局(方向更改、大小更改等)后调用。另外,向集合视图布局询问内容大小更可靠:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Update placeholder constraint
self.heightConstraint.constant = self.collection.collectionViewLayout.collectionViewContentSize.height
}
解决方法如下:
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
}
我有一个使用 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
}
// ...
}
但是当内容布局发生变化时(例如设备方向发生变化),这不会更新集合视图的高度。有没有办法在内容布局发生变化时更新约束常量?或者使用动态约束而不是常量的方法?
Swift4.2,Xcode10.0,目标iOS12.
更新约束的更好位置是 viewDidLayoutSubviews
,它会在每次重新布局(方向更改、大小更改等)后调用。另外,向集合视图布局询问内容大小更可靠:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Update placeholder constraint
self.heightConstraint.constant = self.collection.collectionViewLayout.collectionViewContentSize.height
}
解决方法如下:
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
}