Yuuu
Yuuu

Reputation: 879

How to update the UI when the device orientation changed in Swift?

I was searching how to update the UIs when the device orientation has changed, but I'm stuck now and need some help.

I made a login screen with Swift and created its UIs programmatically. For the supported orientation in the info.plist, I set

and this is the login screen.

enter image description here

When I build and run with Portrait, it works fine, but when I rotate the device, the UI becomes like this.

enter image description here

it's like the device orientation is changed to landscape, but the UI's remain portrait, so the right side of the screen becomes black.

This is the view file (I didn't put the whole code), and I have a stack view contains other UIs.

class LoginView: UIView {
    lazy private var stackView = UIStackView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupStackView()
    }

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


    private func setupStackView() {
        stackView.translatesAutoresizingMaskIntoConstraints = false
        self.addSubview(stackView)
        stackView.axis = .vertical
        stackView.alignment = .fill
        stackView.spacing = 20
        stackView.distribution = .fill
    
        stackView.addArrangedSubview(titleText)
        stackView.addArrangedSubview(greenView)

    
        NSLayoutConstraint.activate([
            stackView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.9),
            stackView.centerXAnchor.constraint(equalTo: self.centerXAnchor),
            stackView.centerYAnchor.constraint(equalTo: self.centerYAnchor)
        ])
    }

and the view controller is like this.

class LoginViewController: UIViewController {

    private let loginView = LoginView()

    override func viewDidLoad() {
    
        view.addSubview(loginView)
        loginView.frame = CGRect(origin: .zero, size: view.bounds.size)
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        print("the view is rotated")
    }
}

I get the message "the view is rotated" printed, and the rotation part seems it does not have a problem, but cannot update the view controller itself to horizontal and update the UIs.

I was wondering why my view controller stays vertical when the device is in landscape mode, and how to update it.

Could anyone please lead me to the right direction, please?

Upvotes: 1

Views: 7350

Answers (1)

Daniel Marx
Daniel Marx

Reputation: 764

Actually by using

loginView.frame = CGRect(origin: .zero, size: view.bounds.size)

you assign a frame to your login view which will not change on device rotation.

you might wanna use a constraint approach here as well:

// try replacing
// loginView.frame = CGRect(origin: .zero, size: view.bounds.size)

// with
 loginView.translatesAutoresizingMaskIntoConstraints = false
 NSLayoutConstraint.activate([
    loginView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
    loginView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
    loginView.topAnchor.constraint(equalTo: view.topAnchor),
    loginView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
 ])

Another approach would be updating the frame of your login view e.g.

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
   super.traitCollectionDidChange(previousTraitCollection)
   loginView.frame = CGRect(origin: .zero, size: view.bounds.size)
}

Last but not least you can use autoresizingMask in viewDidLoad

loginView.frame = CGRect(origin: .zero, size: view.bounds.size)
loginView.autoresizingMask = [.flexibleHeight, .flexibleWidth]

P.S. My previous comment was misleading since the login frame wasn't set in the setupStackView() function

and my final comment:

// you can replace
loginView.frame = CGRect(origin: .zero, size: view.bounds.size)
// with
loginView.frame = view.bounds

Upvotes: 4

Related Questions