Reputation: 3208
I want to change my bearImageView
's width and height to 100 when going from portrait -> landscape, and to 200 when going the opposite direction.
Inside the setupLayout
I am calling deactivating and then activating the constraint on widthAnchor
and heightAnchor
. So I am expecting it to change the width and height.
Problem: It goes to 100, but it does not change back to 200. Why would this happen?
This is the code.
class ViewController: UIViewController {
// closure objects
let bearImageView: UIImageView = {
let imageView = UIImageView(image: #imageLiteral(resourceName: "bear_first")) // type `image literal` and double click
imageView.translatesAutoresizingMaskIntoConstraints = false // enable autolayout
return imageView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(bearImageView) // display image
setupLayout(imageView: bearImageView) // apply constraints
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
if UIDevice.current.orientation.isLandscape {
print("landscape")
setupLayout(imageView: bearImageView) // apply constraints
} else {
print("portrait")
setupLayout(imageView: bearImageView) // apply constraints
}
}
private func setupLayout(imageView: UIImageView){
if UIDevice.current.orientation.isLandscape == true {
imageView.widthAnchor.constraint(equalToConstant: 200).isActive = false
imageView.heightAnchor.constraint(equalToConstant: 200).isActive = false
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
imageView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 100).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 100).isActive = true
print("changed to landscape")
} else {
imageView.widthAnchor.constraint(equalToConstant: 100).isActive = false
imageView.heightAnchor.constraint(equalToConstant: 100).isActive = false
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
imageView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 200).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 200).isActive = true
print("changed to portrait")
}
}
This is the error.
[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:0x6000031923a0 UIImageView:0x7fbf72508060.width == 200 (active)>",
"<NSLayoutConstraint:0x6000031e4730 UIImageView:0x7fbf72508060.width == 100 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x6000031923a0 UIImageView:0x7fbf72508060.width == 200 (active)>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
Upvotes: 0
Views: 975
Reputation: 271820
Note that the constraint
method creates new for your image view.
When you first call setupLayout
in viewDidLoad
, width and height constraints of 200 are added to the image view. Then you rotate the device to change to landscape. setupLayout
is called again. This time it adds width and height constraints of 100, but it does not deactivate the constraints with constant 200 that you previously added. Doing this line:
imageView.widthAnchor.constraint(equalToConstant: 200).isActive = false
Creates a new inactive constraint, not deactivates an old one.
What you should do is to store the width and height constraints as properties of ViewController
:
var widthConstraint: NSLayoutConstraint!
var heightConstraint: NSLayoutConstraint!
And in setupLayout
, assign to those properties:
private func setupLayout(imageView: UIImageView){
widthConstraint = imageView.widthAnchor.constraint(equalToConstant: 200)
heightConstraint = imageView.heightAnchor.constraint(equalToConstant: 200)
widthConstraint.isActive = true
heightConstraint.isActive = true
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
imageView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
}
And you should only call setupLayout
once.
Then you create another method called updateConstraints
that update the constants of widthConstraint
and heightConstraint
:
private func updateConstraints() {
if UIDevice.current.orientation.isLandscape {
heightConstraint.constant = 100
widthConstraint.constant = 100
} else {
heightConstraint.constant = 200
widthConstraint.constant = 200
}
}
Call this in viewWillTransitionToSize
instead of setupLayout
.
Upvotes: 2