0

Within a UITableViewController, UITableViewCell, I've a grid with fixed number of static UICollectionViewCells (without spacing) per row.

extension NounsTVC: UICollectionViewDataSource {

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

    func collectionView( _ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell( withReuseIdentifier: cellIds[indexPath.item], for: indexPath)
        cell.layer.borderColor = UIColor.gray.cgColor
        cell.layer.borderWidth = 0.5
        return cell
    }
}

extension NounsTVC: UICollectionViewDelegateFlowLayout
{
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let availableWidth = collectionView.bounds.size.width
        let minimumWidth = floor(availableWidth / cellsPerRow)
        let remainder = availableWidth - minimumWidth * CGFloat(cellsPerRow)

        let columnIndex = indexPath.row % Int(cellsPerRow)
        let cellWidth = CGFloat(columnIndex) < remainder ? minimumWidth + 1 : minimumWidth
        return CGSize(width: cellWidth, height: 45)
    }
}

Works fine.

But, when I rotate the device, it needs to recall these layout methods.

This looks like the answer: Swift: How to refresh UICollectionView layout after rotation of the device

But I do not have my UICollectionView as invalidLayout() because the UICollectionView is created in IB (as i understand), so how do i call invalidateLayout on my UICollectionView?

Adrian Bobrowski
  • 2,681
  • 1
  • 16
  • 26
DrWhat
  • 2,360
  • 5
  • 19
  • 33
  • Why you don't invalidLayout() of CollectionView? while changing the device orientation – Nikunj Kumbhani Apr 19 '19 at 10:36
  • Do you have access to the `UICollectionView` from the `UITableViewCell`? If yes, override `layoutSubviews` in the `UITableViewCell` and call `invalidateLayout` on the `UICollectionView` there. – surToTheW Apr 19 '19 at 11:48
  • @surToTheW - with cells created static in storyboard, I'm not sure how to instantiate or access the UITableViewCell? @ Nikunj - can you link to full details? will try. – DrWhat Apr 19 '19 at 13:52
  • 1
    I missed the part about static cells. You can provide outlets to them in the TableViewController. Or better an outlet collection. How many cells are they? Then you can override `viewWillTransitionToSize:withTransitionCoordinator:` or `viewWillLayoutSubviews` and call invalidateLayout there on them. – surToTheW Apr 19 '19 at 14:48
  • 1
    @surToTheW - yes, indeed, that is exactly perfect. Thank you. I had trouble making the connection in IB (it wouldn't do it via ctrl-drag and drop), but with your clarification, I coded it in and connected it in reverse, and it now works. THanks again. – DrWhat Apr 21 '19 at 08:38
  • If the collection view outlets are NOT in table view controller, but within a custom UITableViewCell, how do i then call invalidlayout when the device rotates? – DrWhat Apr 29 '19 at 13:53
  • If the collection view outlets are NOT in table view controller, but within a custom UITableViewCell, then the .invalidateLayout can be called within traitCollectionDidChange function. – DrWhat Apr 29 '19 at 14:26

1 Answers1

0

Two problems were identified in the above situation.

Firstly, xcode was not creating an IBOutlet in my custom UITableViewCell by dragging a line between the storyboard and the .swift file (apparently a bug in some constellations). The solution was to type the code in manually, and ctrl-drag and drop this in reverse to the correct view in the storyboard.

@IBOutlet weak var myCollectionView: UICollectionView!

Secondly, because the collection view was instantiated in a custom UITableViewCell, it wasn't possible to use viewWillTransitionToSize:withTransitionCoordinator: or viewWillLayoutSubviews (table view methods). However, UITableViewCell does have the following, where .invalidateLayout() can be called:

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?)
{
    super.traitCollectionDidChange(previousTraitCollection)
    guard previousTraitCollection != nil else
    { return }
    myCollectionView.collectionViewLayout.invalidateLayout()
}
DrWhat
  • 2,360
  • 5
  • 19
  • 33