Jared Pérez
Jared Pérez

Reputation: 43

Constraints not working when device is rotated

I have this UIViewController:

import UIKit

class ViewController: UIViewController {

    var object: DraggableView?

    override func viewDidLoad() {
        super.viewDidLoad() 
        // Create the object
        object = DraggableView(parent: self)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // Add subview
        object?.setup()
    }
}

And I have this class to add the view in this VC:

import UIKit

class DraggableView {

    var parent: UIViewController!

    let pieceOfViewToShow: CGFloat = 30.0

    init(parent: UIViewController) {
        self.parent = parent
    }

    func setup() {
        let view = UIView(frame: parent.view.frame)
        view.backgroundColor = UIColor.red
        parent.view.addSubview(view)
        view.translatesAutoresizingMaskIntoConstraints = false

        view.leadingAnchor.constraint(equalTo: parent.view.safeAreaLayoutGuide.leadingAnchor).isActive = true
        view.trailingAnchor.constraint(equalTo: parent.view.safeAreaLayoutGuide.trailingAnchor).isActive = true
        view.heightAnchor.constraint(equalTo: parent.view.safeAreaLayoutGuide.heightAnchor).isActive = true

        // I need to show only a piece of the view at bottom, so:
        view.topAnchor.constraint(equalTo: parent.view.safeAreaLayoutGuide.topAnchor, constant: parent.view.frame.height - pieceOfViewToShow).isActive = true
    }
}

Problem

Everything is correct but when the device rotates it loses the constraint and the added view is lost.

I think the problem is in the next line that is not able to update the correct height [parent.view.frame.height] when the device is rotated.

view.topAnchor.constraint(equalTo: parent.view.safeAreaLayoutGuide.topAnchor, constant: parent.view.frame.height - pieceOfViewToShow).isActive = true

How could I make to update this constant when rotating? I'm using Swift 3.

Upvotes: 1

Views: 772

Answers (1)

Milan Nosáľ
Milan Nosáľ

Reputation: 19737

You can try using traitCollectionDidChange callback on the UIView to update the constraint when a rotation changes, for that to work you'll need to make DraggableView a subclass of the UIView:

import UIKit

class DraggableView: UIView {

    var parent: UIViewController!

    let pieceOfViewToShow: CGFloat = 30.0

    // keep the constraint around to have access to it
    var topConstraint: NSLayoutConstraint?

    init(parent: UIViewController) {
        super.init(frame: parent.view.frame)
        self.parent = parent
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setup() {
        self.backgroundColor = UIColor.red
        parent.view.addSubview(self)
        self.translatesAutoresizingMaskIntoConstraints = false

        self.leadingAnchor.constraint(equalTo: parent.view.safeAreaLayoutGuide.leadingAnchor).isActive = true
        self.trailingAnchor.constraint(equalTo: parent.view.safeAreaLayoutGuide.trailingAnchor).isActive = true
        self.heightAnchor.constraint(equalTo: parent.view.safeAreaLayoutGuide.heightAnchor).isActive = true

        // keep a reference to the constraint
        topConstraint = self.topAnchor.constraint(equalTo: parent.view.safeAreaLayoutGuide.topAnchor, constant: parent.view.frame.height - pieceOfViewToShow)
        topConstraint?.isActive = true
    }

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

        // update the constraints constant
        topConstraint?.constant = parent.view.frame.height - pieceOfViewToShow
    }
}

Upvotes: 2

Related Questions