user3847113
user3847113

Reputation: 307

UIView frame not updating after orientation change

How to detect orientation change after it happened using Swift 3?

I need to detect it after change to calculate frame size.

EDIT

I asked this question because I need to redraw view on orientation change like in this question: Can't get background gradient to fill entire screen upon rotation

I don't know how to implement answer that is marked as a correct answer.

I tried another answer

self.backgroundImageView.layer.sublayers?.first?.frame = self.view.bounds

but it's not working.

In viewDidLoad() I have

let color1 =  UIColor(red: 225.0/255.0, green: 210.0/255.0, blue: 0.0/255.0, alpha: 1.0).cgColor
let color2 = UIColor(red: 255.0/255.0, green: 125.0/255.0, blue: 77.0/255.0, alpha: 1.0).cgColor

let gradientLayer = CAGradientLayer()
gradientLayer.colors = [color1, color2]
gradientLayer.locations = [ 0.0, 1.0]
gradientLayer.frame = self.view.bounds

self.view.layer.insertSublayer(gradientLayer, at: 0)

Upvotes: 12

Views: 28654

Answers (7)

Sarthak Mishra
Sarthak Mishra

Reputation: 1114

If you are using this to get the updated value of traitCollection, use this instead

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    print("Trait collection changes")

}

Upvotes: 0

Santosh
Santosh

Reputation: 1313

override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) {

    self.sliding.setNeedsDisplay()

}

Upvotes: 0

user7014451
user7014451

Reputation:

Here's my solution, based on these requirements:

(1) My layout needed to change based on which dimension was larger, height or width. (Basically portrait or landscape, but in the future...?)

(2) My app is universal, so I could not consider size classes or any override related to them.

(3) My app also has a photo editing extension, so UIApplication was unavailable. (Also, orientations such as landscapeLeft and landscapeRight do not work in this type of extension.)

NOTE: I'm adding my structure for AutoLayout for completeness.

UIViewController:

var p = [NSLayoutConstraint]()
var l = [NSLayoutConstraint]()
var initialOrientation = true
var isInPortrait = false

override func viewDidLoad() {
    super.viewDidLoad()
    // set up all constraints, including common, portrait and landscape
    setUpConstraints()  
}

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    if initialOrientation {
        initialOrientation = false
        if view.frame.width > view.frame.height {
            isInPortrait = false
        } else {
            isInPortrait = true
        }
        orientationChanged()
    } else {
        if view.orientationHasChanged(&isInPortrait) {
            orientationChanged()
        }
    }
}

func orientationChanged() {
    // this was split out because of other app-specific logic
    view.setOrientation(p, l)
}

UIView:

extension UIView {

    public func orientationHasChanged(_ isInPortrait:inout Bool) -> Bool {
        // always check against isInPortrait to reduce unnecessary AutoLayout changes!
        if self.frame.width > self.frame.height {
            if isInPortrait {
                isInPortrait = false
                return true
            }
        } else {
            if !isInPortrait {
                isInPortrait = true
                return true
            }
        }
        return false
    }
    public func setOrientation(_ p:[NSLayoutConstraint], _ l:[NSLayoutConstraint]) {
        NSLayoutConstraint.deactivate(l)
        NSLayoutConstraint.deactivate(p)
        if self.bounds.width > self.bounds.height {
            NSLayoutConstraint.activate(l)
        } else {
            NSLayoutConstraint.activate(p)
        }
    }
}

Upvotes: 3

LC 웃
LC 웃

Reputation: 18998

The above accepted answer returns frame size before transition.So your view is not updating..You need to get the frame size after the transition has been completed.

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {

        coordinator.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) -> Void in

            let orient = UIApplication.shared.statusBarOrientation

            switch orient {

            case .portrait:

                print("Portrait")

            case .landscapeLeft,.landscapeRight :

                print("Landscape")

            default:

                print("Anything But Portrait")
            }

            }, completion: { (UIViewControllerTransitionCoordinatorContext) -> Void in
                //refresh view once rotation is completed not in will transition as it returns incorrect frame size.Refresh here           

        })
        super.viewWillTransition(to: size, with: coordinator)

    }

Upvotes: 33

Sanjeet Verma
Sanjeet Verma

Reputation: 571

Try this

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    if UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation) {

        print("Landscape mode called")

        if UI_USER_INTERFACE_IDIOM() == .Pad {
            print("Landscape mode in ipad");

        }
        else
        {
            print("Landscape mode in Iphone ")

        }
    } else {
        print("Portrait mode called")
        if UI_USER_INTERFACE_IDIOM() == .Pad {

            print("Portrait mode called in ipad")
        }
        else
        {
            print("Portrait mode called in iphone")
        }
    }
}
override func willRotateToInterfaceOrientation(toInterfaceOrientation:UIInterfaceOrientation, duration: NSTimeInterval) {
    print("willRotateToInterfaceOrientation method called");
    //Here you can invalidateLayout()
}

Upvotes: 0

Rajat
Rajat

Reputation: 11127

To get orientation change callback you need to add this Notification

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

and you need to implement this method

func rotated() {
    if(UIDeviceOrientationIsLandscape(UIDevice.current.orientation))
    {
        print("landscape")
    }

    if(UIDeviceOrientationIsPortrait(UIDevice.current.orientation))
    {
        print("Portrait")
    }
}

Upvotes: 6

Rashwan L
Rashwan L

Reputation: 38833

Add this function and you´ll detect the orientation change:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    if UIDevice.current.orientation.isLandscape {
        print("Landscape")
    } else if UIDevice.current.orientation.isPortrait {
        print("Portrait")
    }
}

Upvotes: 7

Related Questions