Reputation: 307
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
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
Reputation: 1313
override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) {
self.sliding.setNeedsDisplay()
}
Upvotes: 0
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
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
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
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
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