I'm likely going about this in the completely wrong way since what I try to do should be simple... I have a view component which contains a few subviews, one of them being a UICollectionView. I layout the subviews using SnapKit. The UICollectionView is a flowlayout of buttons, spanning over 0-n rows, number of buttons is known from the beginning.
When I configure the constraints via SnapKit the height of the Collection is 0, since no items are present (cellForItemAt still not called).
How would I go about to get the height of the collection to be dynamically set in SnapKit? Or is there a better way to get the very basic flowlayout I'm looking for (with dynamic heigth-adjustement)?
(Note: The code is a bit simplified to only show relevant parts)
class CategoryList: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UICollectionViewDelegate {
var categories : [String]?
var buttons = [BorderedButton]()
private(set) lazy var collectionView: UICollectionView = {
var flowLayout = UICollectionViewFlowLayout()
let collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: flowLayout)
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "collectionCell")
collectionView.delegate = self
collectionView.dataSource = self
collectionView.backgroundColor = UIColor.cyan
return collectionView
}()
override func loadView() {
super.loadView()
self.view.addSubview(collectionView)
}
override func viewDidLoad() {
super.viewDidLoad()
setupConstraints()
}
override func viewDidAppear(_ animated: Bool) {
print("123: \(collectionView.contentSize.height)")
//prints 47 for this particular example, however doing snp.makeConstraints
//(or remakeConstraints) from here doesn't make any difference
//setupConstraints()
}
func configure(categories:[String]) {
self.categories = categories
for category in categories {
let button = BorderedButton()
button.setTitle(category, for: .normal)
buttons.append(button)
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return buttons.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath)
cell.addSubview(buttons[indexPath.row])
//prints 47 for this particular example, however doing snp.makeConstraints
//(or remakeConstraints) from here doesn't make any difference
print("XYZ: \(collectionView.contentSize.height)")
return cell
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize
{
return buttons[indexPath.row].intrinsicContentSize
}
private func setupConstraints() {
collectionView.snp.makeConstraints { (make) in
make.left.top.equalToSuperview()
make.width.equalTo(300)
print("ABC: \(collectionView.contentSize.height)")
//this does not work since height=0
make.height.equalTo(collectionView.contentSize.height)
//this works fine
make.height.equalTo(47)
}
}
}
Thanks!
EDIT: Added missing class
Thanks for the reply below. It indeed works, and great you could get the question even though I missed to include half of the code :-) Below is the missing piece, it is the class using the CategoryList. With your help I get the CategoryList to expand dynamically to the correct height, which is excellent. However, it messes up the placement of the surrounding views (view1 and view2 below). I suspect it has something to do with the
make.height.equalTo(categoryList.collectionView.snp.height)
line, maybe it should just reference the collectionView constraint property instead, but I have no idea how that should (or even could) be done?
class PlaylistDetailsHeaderView : UITableViewCell {
private var categoryList:CategoryList
private(set) lazy var view1: UIView = {
let view = UIView()
return view
}()
private(set) lazy var view2: UIView = {
let view = UIView()
return view
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
self.categoryList = CategoryList()
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.contentView.addSubview(view1)
self.contentView.addSubview(view2)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configure() {
let categories = ["alfa", "beta", "gamma", "fkdiii", "keoooe", "dfdsje", "jkjfldsjflsd", "alfa", "beta", "gamma", "fkdiii", "keoooe", "dfdsje", "jkjfldsjflsd"]
categoryList.configure(categories: categories)
self.contentView.addSubview(categoryList.view)
setupConstraints()
}
private func setupConstraints() {
view1.snp.makeConstraints { make in
make.left.top.equalToSuperview()
}
categoryList.view.snp.makeConstraints{ make in
make.left.equalToSuperview()
make.top.equalTo(view1.snp.bottom).offset(20)
make.width.equalTo(300)
make.height.equalTo(categoryList.collectionView.snp.height)
}
view2.snp.makeConstraints { make in
make.top.equalTo(categoryList.view.snp.bottom).offset(20)
}
}
}