Search code examples
iosswiftuicollectionviewnslayoutconstraintiboutlet

How to set NSLayoutConstraint constant in a collectionView cell?


In my storyboard I have a set of constraints for the subview (called Thumbnail) in a cell

enter image description here

Then in my custom collectionView cell:

class PostViewCell: UICollectionViewCell {

var portrait: Bool? {
    didSet {
        if portrait == true {
            print(self.bounds.height)
            thumbnailWidthConstraint.constant = self.bounds.width
            thumbnailHeightConstraint.constant = self.bounds.height/2
            thumbnailHeightConstraint.isActive = true
        } else {
            thumbnailWidthConstraint.constant = self.bounds.width/2
            thumbnailHeightConstraint.constant = self.bounds.height
        }
        self.layoutIfNeeded()
    }
}
@IBOutlet weak var thumbnailCenterYConstraint: NSLayoutConstraint!
@IBOutlet weak var thumbnailWidthConstraint: NSLayoutConstraint!
@IBOutlet weak var thumbnailHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var thumbnailCenterXConstraint: NSLayoutConstraint!

override func layoutSubviews() {
    if self.bounds.width > self.bounds.height {
        portrait = false
    } else {
        portrait = true
    }
    super.layoutSubviews()
}

}

My goal is to change the height and width of the thumbnail like you see in the didSet method of the portrait variable. However, so far this seems unsuccessful. It prints a self.bounds.height of 536 and in the app it seems to be this height, not half the height as I am trying to set in the constraint. What step am I missing? Why isn't this working? Thanks!

Edit: In my view controller that contains the collectionView cells I have:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    postsCollectionView.collectionViewLayout.invalidateLayout()
    postsCollectionView.layoutIfNeeded()
    super.viewWillTransition(to: size, with: coordinator)
}

this collection view is called "postsCollectionView" in my view controller. Additionally, I have this:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    if collectionView == timelineCollectionView {
        return CGSize(width: CGFloat(2.5), height: collectionView.bounds.height)
    } else {
        return CGSize(width: collectionView.bounds.size.width, height: collectionView.bounds.size.height)
    }
}

Thus when I rotate the phone and the collectionView becomes wider than it is tall, so does the cell inside. This hopefully sets the cell to re-layout subviews and alter the constraints as I have defined.


Solution

  • You may miss re-layout after changing the constant

    var portrait: Bool? {
        didSet {
            if portrait == true {
                print(self.bounds.height)
                thumbnailWidthConstraint.constant = self.bounds.width
                thumbnailHeightConstraint.constant = self.bounds.height/2
                thumbnailHeightConstraint.isActive = true
            } else {
                thumbnailWidthConstraint.constant = self.bounds.width/2
                thumbnailHeightConstraint.constant = self.bounds.height
            }
    
            self.layoutIfNeeded() // or  self.contentView.layoutIfNeeded() 
        }
    }
    

    You need also to respond to system orientation changes

    func viewWillTransition(to size: CGSize, 
                   with coordinator: UIViewControllerTransitionCoordinator) {
      collectionView.collectionViewLayout.invalidateLayout()
      collectionView.layoutIfNeeded()
    }