Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cell size not updating after changing flow layout's itemSize

In my app, I have a full-screen paging collection view and each cell needs to be full-screen as well, so the collection view layout's item size needs to be the same size as the view controller's view's bounds size. To do this, in viewDidLayoutSubviews I'm simply setting the item size and it is working as intended. When I present this screen, viewDidLayoutSubviews is called 3 times and each time the view's bounds size is 375.0 x 667.0 for iPhone 7. The cell is sized those same dimensions as expected.

But when using 3D Touch peek and pop to present this screen, the cell is not sized as expected, neither when peeking nor popping. viewDidLayoutSubviews is called 4 times, with these bounds sizes:

--- peek triggered ---
375.0 x 569.524495677234
375.0 x 569.524495677234
375.0 x 720.821325648415
--- pop triggered ---
375.0 x 667.0

When peeking, the collection view is 'full-screen' as expected with a height of 721, and the cell has the expected width of 375, but the cell height is 569 when it should be 721. Upon popping, the collection view height changes to 667 as expected but the cell height is still 569.

I've tried calling collectionView.layoutIfNeeded() after setting the itemSize but the result is the same. Why isn't the collection view updating the cell size here?

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    print("\(view.bounds.width) x \(view.bounds.height)")

    let boundsSize = CGSize(width: Int(view.bounds.width), height: Int(view.bounds.height))
    let flowLayout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout

    if flowLayout.itemSize != boundsSize {
        flowLayout.itemSize = boundsSize

        collectionView.layoutIfNeeded() //this doens't help
    }
}
like image 327
Jordan H Avatar asked Jul 29 '17 16:07

Jordan H


3 Answers

Change the collection view's 'Estimate Size' from the inspector to 'None'! None of the above answers worked for me.

Estimate Size

like image 70
iqra Avatar answered Nov 16 '22 09:11

iqra


It seems it's a bug of UICollectionViewFlowLayout, I have to call prepare() before invalidateLayout()

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()


    guard let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else
    {
        return
    }

    layout.itemSize = cellSize
    layout.minimumLineSpacing = space
    layout.prepare()  // <-- call prepare before invalidateLayout
    layout.invalidateLayout()
}
like image 44
Chen Jiling Avatar answered Nov 16 '22 07:11

Chen Jiling


Try replacing collectionView.layoutIfNeeded() by flowLayout.invalidateLayout()

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    print("\(view.bounds.width) x \(view.bounds.height)")

    let boundsSize = CGSize(width: Int(view.bounds.width), height: Int(view.bounds.height))
    let flowLayout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout

    if flowLayout.itemSize != boundsSize {
        flowLayout.itemSize = boundsSize

        debugPrint("Called")
        flowLayout.invalidateLayout()
    }
}
like image 1
Reinier Melian Avatar answered Nov 16 '22 09:11

Reinier Melian