I have a use case that seems to fall into the cracks between asset catalogs and size classes. My Universal app needs a full screen background image that is different in Landscape and Portrait orientations, and Landscape is only supported for the iPad & iPhone 6.
Since I can't add landscape images to the asset catalog for a new image set, my current solution looks like this (supports iOS 7 & 8):
// permit landscape mode only for iPads & iPhone 6 (would prefer to use size classes, but...?)
override func shouldAutorotate() -> Bool {
let size = view.frame.size
let maxv = max(size.width, size.height)
return ((maxv > 700.0) || (maxv == 512.0)) ? true : false
}
// this will be triggered only for iOS 7, as long as viewWillTransitionToSize:withTransitionCoordinator: is also implemented!
override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
adjustToOrientation(toInterfaceOrientation)
}
// this will be triggered only for iOS 8
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
let orientation = UIApplication.sharedApplication().statusBarOrientation
// need to reverse the sense of the orientation here; Application still has the previous orientation
switch orientation {
case .Portrait, .PortraitUpsideDown:
adjustToOrientation(.LandscapeLeft)
case .LandscapeLeft, .LandscapeRight:
adjustToOrientation(.Portrait)
default:
adjustToOrientation(.Portrait)
}
}
func adjustToOrientation(newInterfaceOrientation: UIInterfaceOrientation) {
let size = view.frame.size
// rotation already permitted only for iPad & iPhone 6, but need to know which one (size classes useless here?)
switch (max(size.width, size.height)) {
case 1024.0:
if UIInterfaceOrientationIsLandscape(newInterfaceOrientation) {
backgroundImage.image = UIImage(named: "Background-Landscape@2x~ipad.png")
} else {
backgroundImage.image = UIImage(named: "Background@2x~ipad.png")
}
case 736.0:
if UIInterfaceOrientationIsLandscape(newInterfaceOrientation) {
backgroundImage.image = UIImage(named: "Background-Landscape@3x~iphone.png")
} else {
backgroundImage.image = UIImage(named: "Background@3x~iphone.png")
}
case 512.0:
if UIInterfaceOrientationIsLandscape(newInterfaceOrientation) {
backgroundImage.image = UIImage(named: "Background-Landscape~ipad.png")
} else {
backgroundImage.image = UIImage(named: "Background~ipad.png")
}
default:
break
}
}
This works, but seems fragile. Is there a more correct way to identify the device as something that supports a regular size class in Landscape, before actually being in Landscape mode? Or some way that I've missed to specify the Landscape equivalents for an image set?
You can use size classes in assets catalog or you can have two image sets: one for portrait and one for landspace mode. Then you can access images by asset name. This will reduce your code a little. But I'd recommend to cosider using size classes everywhere it's possible.
So the final solution was:
-Set the Width property on the image asset to Any+Regular and added a couple of Landscape images for the iPhone 6+ and iPad, and UIImage automatically does the rest
-A more elegant way to permit rotation only for those two devices, in both iOS 7 & iOS 8:
So all of the above down to 5 lines of code!