Search code examples
swiftnslayoutconstraint

Height constraint, lessThanOrEqualToConstant, but tries to achieve the constant if possible


I have two views, previewSection, & settingsEditSection. I'm trying to layout these views to achieve the following:

  • previewSection's top is anchored to the top of the parent view
  • previewSection has a height of 400 if possible, but it will be smaller if necessary for settingsEditSection to achieve it's minimum height
  • settingsEditSection's top is anchored to bottom of previewSection
  • settingsEditSection's bottom is anchored to bottom of parent view
  • settingsEditSection has a height of at least 150

My problem is, when I give previewSection a height of lessThanOrEqualToConstant: 400 it has an actual height of 0.

Is there some way for me to say: "height of lessThanOrEqualToConstant, x, and as long as theres room, have the height of x"?

I want the height of 150 for settingsEditSection to be the first priority, and then before making it any larger, make previewSection 400 if possible, and if there's still room after that, then settingsEditSection can get larger than 150 to fill in the space.

Here's the code that I wrote, that makes the most sense to me:

let previewSection = PreviewSection()
view.addSubview(previewSection)
let settingsEditSection = SettingsEditSection()
view.addSubview(settingsEditSection)
// Preview section
previewSection.translatesAutoresizingMaskIntoConstraints = false
previewSection.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
previewSection.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
previewSection.topAnchor.constraint(equalTo: view.topAnchor, constant: topMargin).isActive = true
previewSection.heightAnchor.constraint(lessThanOrEqualToConstant: 400).isActive = true
previewSection.bottomAnchor.constraint(equalTo: settingsEditSection.topAnchor).isActive = true
// Settings & edit section
settingsEditSection.translatesAutoresizingMaskIntoConstraints = false
settingsEditSection.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
settingsEditSection.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
settingsEditSection.bottomAnchor.constraint(equalTo: upgradeButton.topAnchor).isActive = true
settingsEditSection.heightAnchor.constraint(greaterThanOrEqualToConstant: 150).isActive = true
settingsEditSection.topAnchor.constraint(equalTo: previewSection.bottomAnchor).isActive = true

Right now, previewSection has a height of 0, and then settingsEditSection's height just spans the entire parent view.

The context of this problem for me is I'm building out this profile page, and to layout the profile & buttons to look best on both an iPhone X and an iPhone 5S, this is the best way to do it.


Solution

  • You can use constraint priority here. After

    previewSection.heightAnchor.constraint(lessThanOrEqualToConstant: 400).isActive = true
    

    You can add one more constraint that gives a default height, but at a lower priority. Like this,

    let previewSectionHeight = previewSection.heightAnchor.constraint(equalToConstant: 400)
    previewSectionHeight.priority = .defaultHigh
    previewSectionHeight.isActive = true
    

    This will make previewSection to have a height of 400 until unless settingsEditSection pushes it up to make it small. For all of this to work you also need to give a constant height to the container view of previewSection and settingsEditSection.