36

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?

Suragch
  • 364,799
  • 232
  • 1,155
  • 1,198
user3193307
  • 413
  • 1
  • 4
  • 8

5 Answers5

79

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.
Bamsworld
  • 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
  • 5
    viewDidLoad 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
18

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
Jon Vogel
  • 4,113
  • 1
  • 28
  • 34
  • 3
    Nice, but cleaner if you remove all occurrences of 'UIUserInterfaceSizeClass' from your example. – JKvr Oct 24 '17 at 12:30
  • 1
    UIScreen.main.traitCollection won't return the same size classes as your view controller in all circumstances though. – ekreloff Mar 02 '18 at 21:42
3

This is nice for testing/debugging:

let sizeClasses = ["Unspecified", "Compact", "Regular"]
print("SizeClass w:\(sizeClasses[traitCollection.horizontalSizeClass.rawValue]) h:\(sizeClasses[traitCollection.verticalSizeClass.rawValue])")
coco
  • 4,650
  • 2
  • 23
  • 31
2

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
Reimond Hill
  • 2,633
  • 21
  • 35
-10

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);
Treverp
  • 19
  • 3