airbnb / MagazineLayout

A collection view layout capable of laying out views in vertically scrolling grids and lists.
Apache License 2.0
3.3k stars 219 forks source link

Layout constraints are breaking when aspect ratio on UIImageView is set #102

Closed iBolom closed 2 years ago

iBolom commented 2 years ago

Describe the bug Well i have collection view cell which contains UIImageView which needs to have 16:9 aspect ratio and two labels below UIImageView. UIImageView needs to be 16:9 and labels below could have dynamic height. If i set aspect ratio on UIImageView 16:9 then i get in debug console this warning: Will attempt to recover by breaking constraint <NSLayoutConstraint:0x60000274edf0 UIImageView:0x12a6287c0.height == 50 (active)>

Besides that when i fast scroll collection view to the bottom layout being totally messed up. I tried also to put low priority for this aspect ratio but then i don't get properly layout(i don't see 2 labels below UIImageView) and when i scroll collection view then cells get bigger(too much).

To Reproduce Steps to reproduce the behaviour:

  1. Create UICollectionViewCell which inherits MagazineLayoutCollectionViewCell.
  2. Create UIImageView and two labels below UIImageView.
  3. Set 16:9 aspect ratio on UIImageView.
  4. Setup constraints between 2x UILabel and UIImageView vertically.

Expected behavior Don't get breaking layout constraints when set aspect ratio 16:9 on UIImageView and fast scrolling should not mess up layout.

Smartphone (please complete the following information):

bryankeller commented 2 years ago

Since the collection view temporarily needs to set the cell to an estimated height (before it self-sizes), your contained view needs to be able to layout at a different height without constraints breaking.

At Airbnb, we do this by setting the priority of our bottom-most constraint to .defaultLow. For example:

let bottomConstraint = label.bottomAnchor.constraint(equalTo: bottomAnchor)
bottomConstraint.priority = .defaultLow

NSLayoutConstraint.activate([
  // imageView constraints

  label.topAnchor.constraint(equalTo: imageView.bottomAnchor),
  label.leadingAnchor.constraint(equalTo: leadingAnchor),
  label.trailingAnchor.constraint(equalTo: trailingAnchor),

  bottomConstraint,
])