This post on teaching students in our iOS immersive size classes and Autolayout was written by iOS Instructor Joe Burgess.
With the introduction of different screen sizes in iOS 8 we now lean more heavily than ever before on AutoLayout to decide where our views belong given different screen sizes. Thankfully, Apple has given us some great tools to write one interface that will expand or contract given different phones and screen sizes.
Apple defines Size Classes like this:
A size class identifies a relative amount of display space for the height and for the width. Each dimension can be either compact, for example, the height of an iPhone in landscape orientation, or regular, for example, the height or width of an iPad. Because much of the layout of an app does not need to change for any available screen size, there is an additional value, any.
Going into the different Size Classes themselves is outside of the scope of this blog post but it boils down to a 2X2 grid of size classes. Here’s a great blog post that explains it in more detail.
Now, there is no concept of “rotation”—simply a change in the size classes being used. If you take a look at Interface Builder there is the size class selector at the bottom. This allows you to set different AutoLayout constraints for different size classes in IB. I really don’t like setting AutoLayout constraints in AutoLayout because I find it confusing, limiting and very hard to teach around.
Whenever I’m teaching, I like to go from the explicit case to the implicit case—and move up layers of abstraction from concrete concepts. This allows students to properly understand what is going on before the “magic” of implicit definitions sets in, instead of just blindly using concepts. Because of this, I start my teaching of AutoLayout with code.
We start very early on with creating instances
NSLayoutConstraint and adding them to the views. There is no ambiguity on what is going on and students gain a much deeper understanding of AutoLayout then if they used Interface Builder. As I prepared for the lecture though, I was curious about how to access the current Size Class from code and to respond to rotation events in the new iOS 8 world.
After searching and searching, I finally discovered that all of the size class information is kept in a UITraitCollection object. There isn’t a ton of documentation on this sadly. If you take a look at the UIViewController documentation you’ll note there is no mention of
UITraitCollection. Looking closer we notice that
UIViewController conforms to the UITraitEnvironemnt protocol. Hark! We found the location of the
UITraitCollection property named
viewDidLoad for your
UIViewController take a look at
self.traitCollection. In it we see all of the visual properties of our device! Here is an example one:
<UITraitCollection: 0x7f833b623e80; _UITraitNameUserInterfaceIdiom = Phone, _UITraitNameDisplayScale = 2.000000, _UITraitNameHorizontalSizeClass = Compact, _UITraitNameVerticalSizeClass = Regular, _UITraitNameTouchLevel = 0, _UITraitNameInteractionModel = 1>
From this we can discover that the device I’m using is a retina (@2x from the
_UITraitNameDisplayScale) phone that is currently in the Compact Horizontal, Regular Vertical size class. That means this is a 3.5”, 4.0” or 4.7” phone in portrait mode. Great, now depending on different Size Classes we can apply different AutoLayout constraints on
Before Size Classes we had a lot of code handling the rotation of the phone in the
willAnimateRotationToInterfaceOrientation:duration: methods in our View Controllers. Apple has changed this with Size Classes. They’ve removed the concept of rotation. When the phone rotates, all that changes is the current Size Class. I love this change. There is no reason to think about how your phone has rotated. All that really matters is the dimensions of the screen are different. This Size Class change is caught in the
traitCollectionDidChange: method. You will be given the previous
UITraitCollection as an argument and are able to access the current
UITraitCollection through the