I'm working with adaptive Layout on iOS 8 and I want to get exactly what the size classes are on viewDidLoad
. Any ideas about that?
- 364,799
- 232
- 1,155
- 1,198
- 413
- 1
- 4
- 8
5 Answers
As of iOS 8 UIViewController adopts the UITraitEnvironment protocol. This protocol declares a property named traitCollection which is of type UITraitCollection. You can therefor access the traitCollection property simply by using self.traitCollection
UITraitCollection has two properties that you want to access named horizontalSizeClass and verticalSizeClass Accessing these properties return an NSInteger. The enum that defines the returned values is declared in official documentation as follows- (this could potentially be added to in the future!)
typedef NS_ENUM (NSInteger, UIUserInterfaceSizeClass {
UIUserInterfaceSizeClassUnspecified = 0,
UIUserInterfaceSizeClassCompact = 1,
UIUserInterfaceSizeClassRegular = 2,
};
So you could get the class and use say a switch to determine your code direction. An example could be -
NSInteger horizontalClass = self.traitCollection.horizontalSizeClass;
NSInteger verticalCass = self.traitCollection.verticalSizeClass;
switch (horizontalClass) {
case UIUserInterfaceSizeClassCompact :
// horizontal is compact class.. do stuff...
break;
case UIUserInterfaceSizeClassRegular :
// horizontal is regular class.. do stuff...
break;
default :
// horizontal is unknown..
break;
}
// continue similarly for verticalClass etc.
- 5,540
- 2
- 30
- 36
-
Just what I needed! Also noted that UIWindow implements UITraitCollection, so you can query the Size Class in your AppDelegate as well. Docs: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITraitCollection_ClassReference/ – MandisaW Oct 29 '15 at 15:12
-
5viewDidLoad is a bad place for doing size clas dependent stuff, as the size class might be unspecified, e.g. when the view does not yet have a superview. A better place is `viewWillLayoutSubViews` according to apple: https://developer.apple.com/videos/play/wwdc2016-233/?time=1263 – fabb Nov 25 '16 at 14:41
Some useful stuff for Swift 4:
UIViewController Extension to get the classes back as a Tuple.
extension UIViewController {
func sizeClass() -> (UIUserInterfaceSizeClass, UIUserInterfaceSizeClass) {
return (self.traitCollection.horizontalSizeClass, self.traitCollection.verticalSizeClass)
}
}
Example Switch statement to consume the function:
switch self.sizeClass() {
case (UIUserInterfaceSizeClass.unspecified, UIUserInterfaceSizeClass.unspecified):
print("Unknown")
case (UIUserInterfaceSizeClass.unspecified, UIUserInterfaceSizeClass.compact):
print("Unknown width, compact height")
case (UIUserInterfaceSizeClass.unspecified, UIUserInterfaceSizeClass.regular):
print("Unknown width, regular height")
case (UIUserInterfaceSizeClass.compact, UIUserInterfaceSizeClass.unspecified):
print("Compact width, unknown height")
case (UIUserInterfaceSizeClass.regular, UIUserInterfaceSizeClass.unspecified):
print("Regular width, unknown height")
case (UIUserInterfaceSizeClass.regular, UIUserInterfaceSizeClass.compact):
print("Regular width, compact height")
case (UIUserInterfaceSizeClass.compact, UIUserInterfaceSizeClass.compact):
print("Compact width, compact height")
case (UIUserInterfaceSizeClass.regular, UIUserInterfaceSizeClass.regular):
print("Regualr width, regular height")
case (UIUserInterfaceSizeClass.compact, UIUserInterfaceSizeClass.regular):
print("Compact width, regular height")
}
Edit/Addition:
If you are trying to access the trait collection early in the UIViewController
's lifecycle they might all be UIUserInterfaceSizeClass.unspecified
.
This can be a pain if you happen to do constraints in code.
I recommend access the .traitCollection
from the UIScreen
shared object.
UIScreen.main.traitCollection
Or even more useful:
UIScreen.main.traitCollection.userInterfaceIdiom
- 4,113
- 1
- 28
- 34
-
3Nice, but cleaner if you remove all occurrences of 'UIUserInterfaceSizeClass' from your example. – JKvr Oct 24 '17 at 12:30
-
1UIScreen.main.traitCollection won't return the same size classes as your view controller in all circumstances though. – ekreloff Mar 02 '18 at 21:42
This is nice for testing/debugging:
let sizeClasses = ["Unspecified", "Compact", "Regular"]
print("SizeClass w:\(sizeClasses[traitCollection.horizontalSizeClass.rawValue]) h:\(sizeClasses[traitCollection.verticalSizeClass.rawValue])")
- 4,650
- 2
- 23
- 31
You can also do it like that in Swift 5
enum DeviceTraitStatus {
///IPAD and others: Width: Regular, Height: Regular
case wRhR
///Any IPHONE Portrait Width: Compact, Height: Regular
case wChR
///IPHONE Plus/Max Landscape Width: Regular, Height: Compact
case wRhC
///IPHONE landscape Width: Compact, Height: Compact
case wChC
static var current:DeviceTraitStatus{
switch (UIScreen.main.traitCollection.horizontalSizeClass, UIScreen.main.traitCollection.verticalSizeClass){
case (UIUserInterfaceSizeClass.regular, UIUserInterfaceSizeClass.regular):
return .wRhR
case (UIUserInterfaceSizeClass.compact, UIUserInterfaceSizeClass.regular):
return .wChR
case (UIUserInterfaceSizeClass.regular, UIUserInterfaceSizeClass.compact):
return .wRhC
case (UIUserInterfaceSizeClass.compact, UIUserInterfaceSizeClass.compact):
return .wChC
default:
return .wChR
}
}
}
The main advantatge is that can be used from not only a UIViewController class dependant and the static method can go into an i.e. Helper class. So you can do somewhere in your code:
let textSize:CGFloat = DeviceTraitStatus.current == .wRhR ? 18:14
- 2,633
- 21
- 35
-
A bit cleaner would be to put the traitStatus inside the enum as a static variable. No need for "MyHelper"... – Joris Weimar Apr 09 '19 at 16:10
-
1
-
Perfect. Though if you want me to further nitpick I would recommend calling the classes wChC, wRhR, etc. to conform with the interface builder naming conventions... :) – Joris Weimar Apr 15 '19 at 18:40
-
@JorisWeimar Thank you again for your feedback. I wish the first time wasn't really bad. I put the old code in a iOS challenge... – Reimond Hill Apr 16 '19 at 06:49
-
-
So for Auto Layout you design your apps' UI per each different size class. The OS does all the work of figuring out the device being used and what size class should be used. However, if you there is a way to figure out what device is being used. I am not sure if you can decided what size class gets used as, again, this is handled dynamically by the OS.
Code for getting device being used:
NSString *device = [[UIDevice currentDevice]model ] ;
NSLog(@"%@",device);
- 19
- 3