In my iPad app, I have a UICollectionView
with dynamic height embedded inside a UITableViewCell
. My issue is when tableView is loaded, the collection view cells are not adjusted properly but as soon as I rotate or change screen orientation, the layout gets adjusted properly.
This is what I am getting at startup:
I am using collectionView's width to calculate width of these cells but I think when tableView is loaded, collectionView inside tableView cell has no proper layout. And this is correct layout after rotating app which I want at startup too:
This is my main cellForRowAt
method for tableView
in main ViewController
:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell
cell.layoutIfNeeded()
// To invalidate layout when screen orientation changes
if let layout = cell.collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.invalidateLayout()
}
cell.heighCollectionView.constant = cell.collectionView.collectionViewLayout.collectionViewContentSize.height
return cell
}
And im just reloading tableView when Screen Orientation changes:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
This is how im calculating layout of the CollectionView Cells:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if traitCollection.horizontalSizeClass == .compact {
let width = self.collectionView.frame.size.width
let height = width / 2
return CGSize(width: width, height: height)
}
else {
let width = (self.collectionView.frame.size.width - 10) / 2
let height = width / 2
return CGSize(width: width, height: height)
}
}
And in CustomTableViewCell
subclass, inside awakeFromNib()
, I am just setting delegate and datasource of collectionView:
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
collectionView.delegate = self
collectionView.dataSource = self
}
My issue is only when View Controller is loaded, how do I set proper layout for collectionView
when its first loaded?
In case you need to see full code, here is the link for the repo: https://github.com/shwaitkumar/RotateCollectionViewInsideTableViewCell.git
CodePudding user response:
When init
ViewController, it get defaults value of height which not the height you calculate. Just at viewDidAppear
reload data of your tableView to get the calculate height.
By the way, in func tableView(_ tableView:, cellForRowAt indexPath:)
just for return cell so please remove calculate height there.
Code will be like this
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.delegate = self
tableView.dataSource = self
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.tableView.reloadData()
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell
//cell.layoutIfNeeded() // removed
// To invalidate layout when screen orientation changes
if let layout = cell.collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.invalidateLayout()
}
//cell.heighCollectionView.constant = cell.collectionView.collectionViewLayout.collectionViewContentSize.height // removed
return cell
}
}