Reputation: 625
I have read posts which say didRotate(from fromInterfaceOrientation is deprecated and advising using viewWillTransitionToSize.
But whenever I try to use this function e.g.
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
if UIDevice.currentDevice().orientation.isLandscape.boolValue {
print("Landscape")
} else {
imageView.image = UIImage(named: const)
}
I get an error which says Method does not override any method of its superclass. I have tried to use the function in both view controller and its view but to no avail.
Upvotes: 0
Views: 2966
Reputation:
If you are using Swift 3, the signature is (for UIViewController):
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
}
See if that helps.
An alternative that should give you the dimensions after rotation is willWillLayoutSubviews()
and viewDidLayoutSubviews()
.(I use the former.) BEWARE: Both may be called several times in a single rotation. Here's my code....
View Controller:
var initialOrientation = true
var isInPortrait = false
override func viewWillLayoutSubviews() {
super.viewDidLayoutSubviews()
if initialOrientation {
initialOrientation = false
if view.frame.width > view.frame.height {
isInPortrait = false
} else {
isInPortrait = true
}
// call initial layout, isInPortrait is set
} else {
if view.orientationHasChanged(&isInPortrait) {
// orientation has changed, isInPortrait is set
}
}
}
UIView extension:
extension UIView {
public func orientationHasChanged(_ isInPortrait:inout Bool) -> Bool {
if self.frame.width > self.frame.height {
if isInPortrait {
isInPortrait = false
return true
}
} else {
if !isInPortrait {
isInPortrait = true
return true
}
}
return false
}
}
EDIT:
16 months later I was asked if I included a typo - should it be viewWillLayoutSubviews
or viewDidLayoutSubviews
. The full answer is "it depends".
The baseline for this question is about the weakness of using viewWillTransitionToSize
, namely, that if you are targeting iPad devices the size class will not change. (Also, note the Will piece of the override - it's triggered before the orientation change.
In my experience, there is no "guarantee" the either viewWillLayoutSubviews
or viewDidLayoutSubviews
will be called only once. But my testing over the years results in viewDidLayoutSubviews
is more likely to be called only once.
More, in the view controller lifecycle, viewDidLoad
will trigger *at least two calls to viewWillLayoutSubviews
with the initial call having a frame of CGRect.zero
.
So if you need to know the orientation change for autolayout constraint activation/deactivation, viewWillLayoutSubviews
will work fine. However, if you wish to manipulate subview frames, viewDidLayoutSubviews
is the proper place for things.
My latest project involves a UIImageView
that uses auto layout to be as large as possible in both orientations. The contentMode
is scaleAspectFit
, so the image itself is automatically resized on an orientation change. The user can use subviews to 'build" a mask (both move and resize), so auto layout won't work here. More, I need to have this mask be "constrained" to the actual image.
So I need to "manually" resize/repostion the mask frame by using both the "will" and "did" pieces of an orientation change. Here's the code I now use. The UIView
extension is still the same, the changes are only in UIViewController
.
var initialOrientation = true
var isInPortrait = false
var orientationDidChange = false
override func viewWillLayoutSubviews() {
super.viewDidLayoutSubviews()
if initialOrientation {
initialOrientation = false
if view.frame.width > view.frame.height {
isInPortrait = false
} else {
isInPortrait = true
}
orientationWillChange()
} else {
if view.orientationHasChanged(&isInPortrait) {
orientationWillChange()
}
}
}
func orientationWillChange() {
// capture the old frame values here, storing in class variables
orientationDidChange = true
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if orientationDidChange {
// change frame for mask and reposition
orientationDidChange = false
}
}
Upvotes: 1