iosswiftnotificationcenter

How to get the screen height after orientation change?


I'm getting some strange results when querying UIScreen.main.bounds.height after an orientation change. Maybe this isn't the correct way to do it.

I have an observer that listens for the NSNotification.Name.UIDeviceOrientationDidChange event:

NotificationCenter.default.addObserver(self, selector: #selector(self.orientationChange), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)

This calls a function that sets a constraint to 75% of the new screen height. This works fine on iPhone but iPad returns the wrong screen height.

If the iPad is in landscape orientation UIScreen.main.bounds.height will return a value equal to the height in portrait orientation and vice versa.

func orientationChange() {
    // This will print the correct value on iPhone and iPad.
    if UIDevice.current.orientation.isLandscape {
        print("Landscape")
    } else {
        print("Portrait")
    }

    let screenSize = UIScreen.main.bounds
    let screenHeight = screenSize.height
    self.searchViewHeightConstraint.constant = screenHeight * 0.75

    // Correct value on iPhone. Incorrect on iPad.
    print("screenHeight: '\(screenHeight)'") 

    UIView.animate(withDuration: 0.6, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: .curveEaseOut, animations: {
        self.searchView.superview?.layoutIfNeeded()
    }, completion: nil)
}

I've also come across the viewWilltransition method of monitoring orientation change but this behaves in the exact opposite way to the method above. ie. the height is correct on iPad but incorrect on iPhone:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    let screenSize = UIScreen.main.bounds
    let screenHeight = screenSize.height
    self.searchViewHeightConstraint.constant = screenHeight * 0.75

    // Correct value on iPad. Incorrect on iPhone.
    print("screenHeight: '\(screenHeight)'") 
}

What is the reason for this inconsistent behaviour between iPhone and iPad and is using NotificationCenter the correct approach to monitoring orientation change?


Solution

  • What you should be using is viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator). This will give you the size and is WAY more reliable than using a notification.

    Also, if you wanted to do animations, inside of the UIViewControllerTransitionCoordinator you can leverage the method animate(alongsideTransition animation: ((UIViewControllerTransitionCoordinatorContext) -> Swift.Void)?, completion: ((UIViewControllerTransitionCoordinatorContext) -> Swift.Void)? = nil) -> Bool