简体   繁体   中英

Swift 4: UI fails to update after device rotation

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.

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM