Bob
Bob

Reputation: 179

Unable to switch between programmable constraints

I am trying to toggle between two programmable view constraints, depending on the orientation of the device.

To toggle I set the old height/width constraints to isActive=False in viewWillLayoutSubviews() and the new constraints to isActive=True in viewDiDLayoutSubViews(), however I get an

“unable to simultaneously satisfy constraints”

error in the debug, and it blocks the newConstraints.

Any advice on where to block the old constraints?

The IBOutlet for my View is set to ‘Strong’. I have also tried applying .layoutIfNeeded after changing the old constraint to isActive=False, but it still seems to be active.

Please see pertinent code below. The layout works well initially however after device rotation the new constraints in the updateViewLayouts method get blocked. I believe the new constraints are correct, I just need to disable the old constraints at the correct time.

override func viewWillLayoutSubviews() {
    super.viewDidLayoutSubviews()
    if view.orientationHasChanged(&isInPortrait) {
        orientationWillChange()
    }
    if isInPortrait { //Disable Landscape constraints
        imageView1.heightAnchor.constraint(equalTo: frameView.heightAnchor, multiplier: 1.0).isActive = false
        imageView1.widthAnchor.constraint(equalTo: frameView.widthAnchor, multiplier: 0.5).isActive = false
    } else {   //Disable Portrait constraints
        imageView1.heightAnchor.constraint(equalTo: frameView.heightAnchor, multiplier: 0.5).isActive = false
        imageView1.widthAnchor.constraint(equalTo: frameView.widthAnchor, multiplier: 1.0).isActive = false
    }
    imageView1.layoutIfNeeded()
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    if orientationDidChange {
        updateViewLayouts()
        orientationDidChange = false
    }
}

func updateViewLayouts() {
    imageView1.topAnchor.constraint(equalTo: frameView.topAnchor).isActive = true
    imageView1.leadingAnchor.constraint(equalTo: frameView.leadingAnchor).isActive = true
    if isInPortrait {
        imageView1.heightAnchor.constraint(equalTo: frameView.heightAnchor, multiplier: 0.5).isActive = true
        imageView1.widthAnchor.constraint(equalTo: frameView.widthAnchor, multiplier: 1.0).isActive = true
    } else { //LANDSCAPE
        imageView1.heightAnchor.constraint(equalTo: frameView.heightAnchor, multiplier: 1.0).isActive = true
        imageView1.widthAnchor.constraint(equalTo: frameView.widthAnchor, multiplier: 0.5).isActive = true
    }
}

Upvotes: 1

Views: 77

Answers (1)

Mojtaba Hosseini
Mojtaba Hosseini

Reputation: 119666

This is not how it works

imageView1.heightAnchor.constraint(equalTo: frameView.heightAnchor, multiplier: 1.0).isActive = false

Because every time you call .constraint(..., it creates new constraint and return it back to you. So setting it to false is none sense because it's will create and destroy at the same time.

For disabling that, you need to take a reference to the constraint, and deactivate that later:

//Persistant variable
var portraitHeightConstraint: NSLayoutConstraint?

// If portrait
portraitHeightConstraint = imageView1.heightAnchor.constraint(equalTo: frameView.heightAnchor, multiplier: 1.0)
portraitHeightConstraint?.isActive = true

// And later if needed
portraitHeightConstraint?.isActive = false

// And same logic for horizontal and other constraints

Please note that I write this without compiler and may have some syntax errors. Don't panic.

Upvotes: 1

Related Questions