4

I’ve been trying to get up and running with building adaptive layouts in pure code (no storyboards used). I use layout anchors to set constraints and utilize traitCollectionDidChange method to vary between various sets of constraints and other interface changes. I use a switch statement to call the corresponding method with the corresponding set of constraints.

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)

    switch (traitCollection.horizontalSizeClass, traitCollection.verticalSizeClass) {
    case (.regular, .regular):
        setupRegularRegular()

    case (.compact, .compact):
        setupCompactCompact()

    case (.regular, .compact):
        setupRegularCompact()

    case (.compact, .regular):
        setupCompactRegular()

    default: break
    }

}

For the sake of testing, I changed only one constraint, which is centerYAnchor.constraint. In portrait the constant is -150, in landscape I want it to be changed to 50. For iPad, I set the constant to 0.

bigLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -150).isActive = true

It works fine when switching between iPhone and iPad. However, if you start rotating the iPhone from portrait to landscape, the layout system fails, saying:

[LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. 
Try this: 
    (1) look at each constraint and try to figure out which you don't expect; 
    (2) find the code that added the unwanted constraint or constraints and fix it. 
(
"<NSLayoutConstraint:0x600000097890 UILabel:0x7fac02c08aa0'Main Label'.centerY == UIView:0x7fac02e0a950.centerY - 150   (active)>",
"<NSLayoutConstraint:0x604000097840 UILabel:0x7fac02c08aa0'Main Label'.centerY == UIView:0x7fac02e0a950.centerY + 50   (active)>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x604000097840 UILabel:0x7fac02c08aa0'Main Label'.centerY == UIView:0x7fac02e0a950.centerY + 50   (active)>

I tried overriding various methods and setting the isActive property of the constraint to false and then back to true, but that didn’t help. I searched the web for a couple of days. No solution so far. So my question is, how do you actually switch between size classes the right way when rotating the device? Is it necessary to override any other method or something? Is there a better solution for adaptive layout in pure code? Are there any best practices when it comes to adaptive layouts / size classes / layout anchors and constraints in code (without using the storyboard)? Thanks for help!

P.S. the methods setting up constraints are:

func setupCompactRegular() {

    bigLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -150).isActive = true

}

func setupRegularCompact() {

    bigLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 50).isActive = true

}
General Grievance
  • 4,555
  • 31
  • 31
  • 45
Andrei
  • 71
  • 1
  • 6

1 Answers1

5

the issue is you are creating new constraints.. try holding a reference to your constraint and change your methods to update them

func setupCompactRegular() {

    self.bigLabelCenterYAnchor.constant = -150

}

func setupRegularCompact() {

    self.bigLabelCenterYAnchor.constant = 50

}

Call layoutIfNeeded() right after if it doesnt update automatically

  • 1
    Thanks a lot for your help, but I'm new to this stuff and I'm having a hard time figuring out how to hold reference to my constraints. Could you please specify in code what exactly goes where, how to create and hold the reference and where exactly to call layoutIfNeeded()? Thanks a million! – Andrei Aug 15 '17 at 05:46
  • 1
    P.S. What is bigLabelCenterYAnchor? Is it a global variable or some kind of a property of type CGFloat or what? If so, where should it be created and how to apply it when using anchors? Or maybe you meant self.bigLabel.centerYAnchor? If so, then there is no such member as constant. Sorry for those newbie questions but I'm overwhelmed by this stuff. – Andrei Aug 15 '17 at 05:58