Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS- Detect current size classes on viewDidLoad

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?

like image 788
user3193307 Avatar asked Apr 09 '15 02:04

user3193307


3 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.
like image 67
Bamsworld Avatar answered Nov 11 '22 11:11

Bamsworld


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
like image 20
Jon Vogel Avatar answered Nov 11 '22 12:11

Jon Vogel


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
like image 4
Reimond Hill Avatar answered Nov 11 '22 11:11

Reimond Hill